mirror of
https://github.com/golang/go
synced 2024-09-04 23:44:16 +00:00
[dev.typeparams] all: merge master (296ddf2
) into dev.typeparams
Conflicts: - src/runtime/runtime2.go On master, CL 317191 fixed the mentions of gc/reflect.go in comments to reflectdata/reflect.go; but on dev.typeparams, CL 325921 fixed that the same comment to reflect that deferstruct actually ended up in ssagen/ssa.go. Merge List: + 2021-07-08296ddf2a93
net: filter bad names from Lookup functions instead of hard failing + 2021-07-08ce76298ee7
Update oudated comment + 2021-07-082ca44fe221
doc/go1.17: linkify time.UnixMilli and time.UnixMicro + 2021-07-075c59e11f5e
cmd/compile: remove special-casing of blank in types.sconv{,2} + 2021-07-07b003a8b1ae
cmd/compile: optimize types.sconv + 2021-07-0711f5df2d67
cmd/compile: extract pkgqual from symfmt + 2021-07-07991fd381d5
cmd/go: don't lock .mod and .sum files for read in overlay + 2021-07-07186a3bb4b0
cmd/go/internal/modfetch/codehost: skip hg tests if no hg binary is present + 2021-07-0700c00558e1
cmd/go/internal/modload: remove unused functions + 2021-07-07f264879f74
cmd/go/internal/modload: fix an apparent typo in the AutoRoot comment + 2021-07-07c96833e5ba
doc: remove stale comment about arm64 port Change-Id: I849046b6d8f7421f60323549f3f763ef418bf9e7
This commit is contained in:
commit
2b1d70a137
|
@ -827,10 +827,6 @@ The other codes are <code>-></code> (arithmetic right shift),
|
||||||
|
|
||||||
<h3 id="arm64">ARM64</h3>
|
<h3 id="arm64">ARM64</h3>
|
||||||
|
|
||||||
<p>
|
|
||||||
The ARM64 port is in an experimental state.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<code>R18</code> is the "platform register", reserved on the Apple platform.
|
<code>R18</code> is the "platform register", reserved on the Apple platform.
|
||||||
To prevent accidental misuse, the register is named <code>R18_PLATFORM</code>.
|
To prevent accidental misuse, the register is named <code>R18_PLATFORM</code>.
|
||||||
|
|
|
@ -1132,10 +1132,13 @@ func Foo() bool {
|
||||||
|
|
||||||
<p><!-- CL 293349 -->
|
<p><!-- CL 293349 -->
|
||||||
The new <a href="/pkg/time/#Time.UnixMilli"><code>Time.UnixMilli</code></a> and
|
The new <a href="/pkg/time/#Time.UnixMilli"><code>Time.UnixMilli</code></a> and
|
||||||
<a href="/pkg/time/#Time.UnixMicro"><code>Time.UnixMicro</code></a> methods return the number of milliseconds and
|
<a href="/pkg/time/#Time.UnixMicro"><code>Time.UnixMicro</code></a>
|
||||||
microseconds elapsed since January 1, 1970 UTC respectively.<br>
|
methods return the number of milliseconds and microseconds elapsed since
|
||||||
The new <code>UnixMilli</code> and <code>UnixMicro</code> functions return local Time corresponding to given
|
January 1, 1970 UTC respectively.
|
||||||
Unix time.
|
<br />
|
||||||
|
The new <a href="/pkg/time/#UnixMilli"><code>UnixMilli</code></a> and
|
||||||
|
<a href="/pkg/time/#UnixMicro"><code>UnixMicro</code></a> functions
|
||||||
|
return the local <code>Time</code> corresponding to the given Unix time.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p><!-- CL 300996 -->
|
<p><!-- CL 300996 -->
|
||||||
|
|
|
@ -651,7 +651,7 @@ var kinds = []int{
|
||||||
// tflag is documented in reflect/type.go.
|
// tflag is documented in reflect/type.go.
|
||||||
//
|
//
|
||||||
// tflag values must be kept in sync with copies in:
|
// 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
|
// cmd/link/internal/ld/decodesym.go
|
||||||
// reflect/type.go
|
// reflect/type.go
|
||||||
// runtime/type.go
|
// runtime/type.go
|
||||||
|
|
|
@ -109,14 +109,18 @@ func sconv(s *Sym, verb rune, mode fmtMode) string {
|
||||||
return "<S>"
|
return "<S>"
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Name == "_" {
|
q := pkgqual(s.Pkg, verb, mode)
|
||||||
return "_"
|
if q == "" {
|
||||||
|
return s.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := fmtBufferPool.Get().(*bytes.Buffer)
|
buf := fmtBufferPool.Get().(*bytes.Buffer)
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
defer fmtBufferPool.Put(buf)
|
defer fmtBufferPool.Put(buf)
|
||||||
|
|
||||||
symfmt(buf, s, verb, mode)
|
buf.WriteString(q)
|
||||||
|
buf.WriteByte('.')
|
||||||
|
buf.WriteString(s.Name)
|
||||||
return InternString(buf.Bytes())
|
return InternString(buf.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,56 +132,49 @@ func sconv2(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
|
||||||
b.WriteString("<S>")
|
b.WriteString("<S>")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.Name == "_" {
|
|
||||||
b.WriteString("_")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
symfmt(b, s, verb, mode)
|
symfmt(b, s, verb, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func symfmt(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' {
|
if verb != 'S' {
|
||||||
switch mode {
|
switch mode {
|
||||||
case fmtGo: // This is for the user
|
case fmtGo: // This is for the user
|
||||||
if s.Pkg == BuiltinPkg || s.Pkg == LocalPkg {
|
if pkg == BuiltinPkg || pkg == LocalPkg {
|
||||||
b.WriteString(s.Name)
|
return ""
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the name was used by multiple packages, display the full path,
|
// If the name was used by multiple packages, display the full path,
|
||||||
if s.Pkg.Name != "" && NumImport[s.Pkg.Name] > 1 {
|
if pkg.Name != "" && NumImport[pkg.Name] > 1 {
|
||||||
fmt.Fprintf(b, "%q.%s", s.Pkg.Path, s.Name)
|
return strconv.Quote(pkg.Path)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
b.WriteString(s.Pkg.Name)
|
return pkg.Name
|
||||||
b.WriteByte('.')
|
|
||||||
b.WriteString(s.Name)
|
|
||||||
return
|
|
||||||
|
|
||||||
case fmtDebug:
|
case fmtDebug:
|
||||||
b.WriteString(s.Pkg.Name)
|
return pkg.Name
|
||||||
b.WriteByte('.')
|
|
||||||
b.WriteString(s.Name)
|
|
||||||
return
|
|
||||||
|
|
||||||
case fmtTypeIDName:
|
case fmtTypeIDName:
|
||||||
// dcommontype, typehash
|
// dcommontype, typehash
|
||||||
b.WriteString(s.Pkg.Name)
|
return pkg.Name
|
||||||
b.WriteByte('.')
|
|
||||||
b.WriteString(s.Name)
|
|
||||||
return
|
|
||||||
|
|
||||||
case fmtTypeID:
|
case fmtTypeID:
|
||||||
// (methodsym), typesym, weaksym
|
// (methodsym), typesym, weaksym
|
||||||
b.WriteString(s.Pkg.Prefix)
|
return pkg.Prefix
|
||||||
b.WriteByte('.')
|
|
||||||
b.WriteString(s.Name)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.WriteString(s.Name)
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type
|
// Type
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"cmd/go/internal/fsys"
|
|
||||||
"cmd/go/internal/lockedfile/internal/filelock"
|
"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
|
// calls for Linux and Windows anyway, so it's simpler to use that approach
|
||||||
// consistently.
|
// consistently.
|
||||||
|
|
||||||
f, err := fsys.OpenFile(name, flag&^os.O_TRUNC, perm)
|
f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"cmd/go/internal/fsys"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Opening an exclusive-use file returns an error.
|
// 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
|
// 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
|
// have the ModeExclusive bit set. Set it before we call OpenFile, so that we
|
||||||
// can be confident that a successful OpenFile implies exclusive use.
|
// 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 fi.Mode()&fs.ModeExclusive == 0 {
|
||||||
if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil {
|
if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -72,7 +70,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
|
||||||
nextSleep := 1 * time.Millisecond
|
nextSleep := 1 * time.Millisecond
|
||||||
const maxSleep = 500 * time.Millisecond
|
const maxSleep = 500 * time.Millisecond
|
||||||
for {
|
for {
|
||||||
f, err := fsys.OpenFile(name, flag, perm|fs.ModeExclusive)
|
f, err := os.OpenFile(name, flag, perm|fs.ModeExclusive)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
@ -47,12 +46,6 @@ var altRepos = []string{
|
||||||
var localGitRepo string
|
var localGitRepo string
|
||||||
|
|
||||||
func testMain(m *testing.M) int {
|
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-")
|
dir, err := os.MkdirTemp("", "gitrepo-test-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
@ -60,23 +53,25 @@ func testMain(m *testing.M) int {
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
if testenv.HasExternalNetwork() && testenv.HasExec() {
|
if testenv.HasExternalNetwork() && testenv.HasExec() {
|
||||||
// Clone gitrepo1 into a local directory.
|
if _, err := exec.LookPath("git"); err == nil {
|
||||||
// If we use a file:// URL to access the local directory,
|
// Clone gitrepo1 into a local directory.
|
||||||
// then git starts up all the usual protocol machinery,
|
// If we use a file:// URL to access the local directory,
|
||||||
// which will let us test remote git archive invocations.
|
// then git starts up all the usual protocol machinery,
|
||||||
localGitRepo = filepath.Join(dir, "gitrepo2")
|
// which will let us test remote git archive invocations.
|
||||||
if _, err := Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil {
|
localGitRepo = filepath.Join(dir, "gitrepo2")
|
||||||
log.Fatal(err)
|
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 := Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.Run()
|
return m.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRepo(remote string) (Repo, error) {
|
func testRepo(t *testing.T, remote string) (Repo, error) {
|
||||||
if remote == "localGitRepo" {
|
if remote == "localGitRepo" {
|
||||||
// Convert absolute path to file URL. LocalGitRepo will not accept
|
// Convert absolute path to file URL. LocalGitRepo will not accept
|
||||||
// Windows absolute paths because they look like a host:path remote.
|
// Windows absolute paths because they look like a host:path remote.
|
||||||
|
@ -87,15 +82,17 @@ func testRepo(remote string) (Repo, error) {
|
||||||
} else {
|
} else {
|
||||||
url = "file:///" + filepath.ToSlash(localGitRepo)
|
url = "file:///" + filepath.ToSlash(localGitRepo)
|
||||||
}
|
}
|
||||||
|
testenv.MustHaveExecPath(t, "git")
|
||||||
return LocalGitRepo(url)
|
return LocalGitRepo(url)
|
||||||
}
|
}
|
||||||
kind := "git"
|
vcs := "git"
|
||||||
for _, k := range []string{"hg"} {
|
for _, k := range []string{"hg"} {
|
||||||
if strings.Contains(remote, "/"+k+"/") {
|
if strings.Contains(remote, "/"+k+"/") {
|
||||||
kind = k
|
vcs = k
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NewRepo(kind, remote)
|
testenv.MustHaveExecPath(t, vcs)
|
||||||
|
return NewRepo(vcs, remote)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagsTests = []struct {
|
var tagsTests = []struct {
|
||||||
|
@ -116,7 +113,7 @@ func TestTags(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range tagsTests {
|
for _, tt := range tagsTests {
|
||||||
f := func(t *testing.T) {
|
f := func(t *testing.T) {
|
||||||
r, err := testRepo(tt.repo)
|
r, err := testRepo(t, tt.repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -168,7 +165,7 @@ func TestLatest(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range latestTests {
|
for _, tt := range latestTests {
|
||||||
f := func(t *testing.T) {
|
f := func(t *testing.T) {
|
||||||
r, err := testRepo(tt.repo)
|
r, err := testRepo(t, tt.repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -221,7 +218,7 @@ func TestReadFile(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range readFileTests {
|
for _, tt := range readFileTests {
|
||||||
f := func(t *testing.T) {
|
f := func(t *testing.T) {
|
||||||
r, err := testRepo(tt.repo)
|
r, err := testRepo(t, tt.repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -412,7 +409,7 @@ func TestReadZip(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range readZipTests {
|
for _, tt := range readZipTests {
|
||||||
f := func(t *testing.T) {
|
f := func(t *testing.T) {
|
||||||
r, err := testRepo(tt.repo)
|
r, err := testRepo(t, tt.repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -581,7 +578,7 @@ func TestStat(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range statTests {
|
for _, tt := range statTests {
|
||||||
f := func(t *testing.T) {
|
f := func(t *testing.T) {
|
||||||
r, err := testRepo(tt.repo)
|
r, err := testRepo(t, tt.repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
|
"cmd/go/internal/fsys"
|
||||||
"cmd/go/internal/lockedfile"
|
"cmd/go/internal/lockedfile"
|
||||||
"cmd/go/internal/par"
|
"cmd/go/internal/par"
|
||||||
"cmd/go/internal/robustio"
|
"cmd/go/internal/robustio"
|
||||||
|
@ -416,7 +417,18 @@ func initGoSum() (bool, error) {
|
||||||
|
|
||||||
goSum.m = make(map[module.Version][]string)
|
goSum.m = make(map[module.Version][]string)
|
||||||
goSum.status = make(map[modSum]modSumStatus)
|
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) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -716,6 +728,9 @@ Outer:
|
||||||
if cfg.BuildMod == "readonly" {
|
if cfg.BuildMod == "readonly" {
|
||||||
base.Fatalf("go: updates to go.sum needed, disabled by -mod=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
|
// Make a best-effort attempt to acquire the side lock, only to exclude
|
||||||
// previous versions of the 'go' command from making simultaneous edits.
|
// previous versions of the 'go' command from making simultaneous edits.
|
||||||
|
|
|
@ -71,7 +71,7 @@ type Root int
|
||||||
const (
|
const (
|
||||||
// AutoRoot is the default for most commands. modload.Init will look for
|
// 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,
|
// 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.
|
// limited module mode.
|
||||||
AutoRoot Root = iota
|
AutoRoot Root = iota
|
||||||
|
|
||||||
|
@ -412,7 +412,16 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
gomod := ModFilePath()
|
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 {
|
if err != nil {
|
||||||
base.Fatalf("go: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1026,6 +1035,13 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements)
|
||||||
}
|
}
|
||||||
return
|
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()
|
new, err := modFile.Format()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -675,20 +675,6 @@ func DirImportPath(ctx context.Context, dir string) string {
|
||||||
return "."
|
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
|
// ImportMap returns the actual package import path
|
||||||
// for an import path found in source code.
|
// for an import path found in source code.
|
||||||
// If the given import path does not appear in the 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
|
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
|
// Lookup returns the source directory, import path, and any loading error for
|
||||||
// the package at path as imported from the package in parentDir.
|
// the package at path as imported from the package in parentDir.
|
||||||
// Lookup requires that one of the Load functions in this package has already
|
// Lookup requires that one of the Load functions in this package has already
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -15,6 +16,7 @@ import (
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
|
"cmd/go/internal/fsys"
|
||||||
"cmd/go/internal/lockedfile"
|
"cmd/go/internal/lockedfile"
|
||||||
"cmd/go/internal/modfetch"
|
"cmd/go/internal/modfetch"
|
||||||
"cmd/go/internal/par"
|
"cmd/go/internal/par"
|
||||||
|
@ -601,8 +603,16 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) {
|
||||||
dir = filepath.Join(ModRoot(), dir)
|
dir = filepath.Join(ModRoot(), dir)
|
||||||
}
|
}
|
||||||
gomod := filepath.Join(dir, "go.mod")
|
gomod := filepath.Join(dir, "go.mod")
|
||||||
|
var data []byte
|
||||||
data, err := lockedfile.Read(gomod)
|
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 {
|
if err != nil {
|
||||||
return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))}
|
return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))}
|
||||||
}
|
}
|
||||||
|
|
|
@ -920,8 +920,8 @@ func (e *PackageNotInModuleError) ImportPath() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModuleHasRootPackage returns whether module m contains a package m.Path.
|
// moduleHasRootPackage returns whether module m contains a package m.Path.
|
||||||
func ModuleHasRootPackage(ctx context.Context, m module.Version) (bool, error) {
|
func moduleHasRootPackage(ctx context.Context, m module.Version) (bool, error) {
|
||||||
needSum := false
|
needSum := false
|
||||||
root, isLocal, err := fetch(ctx, m, needSum)
|
root, isLocal, err := fetch(ctx, m, needSum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
10
src/cmd/go/testdata/script/mod_overlay.txt
vendored
10
src/cmd/go/testdata/script/mod_overlay.txt
vendored
|
@ -21,7 +21,7 @@ go list -deps -overlay overlay.json .
|
||||||
cd $WORK/gopath/src/get-doesnt-add-dep
|
cd $WORK/gopath/src/get-doesnt-add-dep
|
||||||
cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
|
cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
|
||||||
! go get -d -overlay overlay.json .
|
! 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
|
cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
|
||||||
|
|
||||||
# Content of overlaid go.sum is used.
|
# Content of overlaid go.sum is used.
|
||||||
|
@ -41,10 +41,10 @@ go mod verify -overlay overlay.json
|
||||||
# attempting to update the file
|
# attempting to update the file
|
||||||
cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
|
cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
|
||||||
! go get -d -overlay overlay.json .
|
! 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
|
cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
|
||||||
! go mod tidy -overlay overlay.json
|
! 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
|
cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
|
||||||
|
|
||||||
# -overlay works with -modfile.
|
# -overlay works with -modfile.
|
||||||
|
@ -56,7 +56,7 @@ go list -modfile=alternate.mod -overlay overlay.json .
|
||||||
stdout 'found.the/module'
|
stdout 'found.the/module'
|
||||||
# Even with -modfile, overlaid files can't be opened for write.
|
# Even with -modfile, overlaid files can't be opened for write.
|
||||||
! go get -modfile=alternate.mod -overlay overlay.json -d rsc.io/quote
|
! 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
|
# Carving out a module by adding an overlaid go.mod file
|
||||||
cd $WORK/gopath/src/carve
|
cd $WORK/gopath/src/carve
|
||||||
|
@ -78,7 +78,7 @@ go list -overlay overlay.json all
|
||||||
stdout ^carve2/nomod$
|
stdout ^carve2/nomod$
|
||||||
# Editing go.mod file fails because overlay is read only
|
# Editing go.mod file fails because overlay is read only
|
||||||
! go get -overlay overlay.json -d rsc.io/quote
|
! 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
|
! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod
|
||||||
# Editing go.mod file succeeds because we use -modfile to redirect to same file
|
# 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
|
go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod -d rsc.io/quote
|
||||||
|
|
|
@ -16,12 +16,12 @@ import (
|
||||||
|
|
||||||
// Decoding the type.* symbols. This has to be in sync with
|
// Decoding the type.* symbols. This has to be in sync with
|
||||||
// ../../runtime/type.go, or more specifically, with what
|
// ../../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 is documented in reflect/type.go.
|
||||||
//
|
//
|
||||||
// tflag values must be kept in sync with copies in:
|
// 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
|
// cmd/link/internal/ld/decodesym.go
|
||||||
// reflect/type.go
|
// reflect/type.go
|
||||||
// runtime/type.go
|
// runtime/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.
|
* A few are known to ../runtime/type.go to convey to debuggers.
|
||||||
* They are also known to ../runtime/type.go.
|
* They are also known to ../runtime/type.go.
|
||||||
*/
|
*/
|
||||||
|
@ -111,7 +111,7 @@ const (
|
||||||
// available in the memory directly following the rtype value.
|
// available in the memory directly following the rtype value.
|
||||||
//
|
//
|
||||||
// tflag values must be kept in sync with copies in:
|
// 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
|
// cmd/link/internal/ld/decodesym.go
|
||||||
// runtime/type.go
|
// runtime/type.go
|
||||||
type tflag uint8
|
type tflag uint8
|
||||||
|
|
|
@ -1846,6 +1846,17 @@ func TestCVE202133195(t *testing.T) {
|
||||||
Target: dnsmessage.MustNewName("<html>.golang.org."),
|
Target: dnsmessage.MustNewName("<html>.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:
|
case dnsmessage.TypeMX:
|
||||||
r.Answers = append(r.Answers,
|
r.Answers = append(r.Answers,
|
||||||
|
@ -1860,6 +1871,17 @@ func TestCVE202133195(t *testing.T) {
|
||||||
MX: dnsmessage.MustNewName("<html>.golang.org."),
|
MX: dnsmessage.MustNewName("<html>.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:
|
case dnsmessage.TypeNS:
|
||||||
r.Answers = append(r.Answers,
|
r.Answers = append(r.Answers,
|
||||||
|
@ -1874,6 +1896,17 @@ func TestCVE202133195(t *testing.T) {
|
||||||
NS: dnsmessage.MustNewName("<html>.golang.org."),
|
NS: dnsmessage.MustNewName("<html>.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:
|
case dnsmessage.TypePTR:
|
||||||
r.Answers = append(r.Answers,
|
r.Answers = append(r.Answers,
|
||||||
|
@ -1888,6 +1921,17 @@ func TestCVE202133195(t *testing.T) {
|
||||||
PTR: dnsmessage.MustNewName("<html>.golang.org."),
|
PTR: dnsmessage.MustNewName("<html>.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
|
return r, nil
|
||||||
|
@ -1903,59 +1947,139 @@ func TestCVE202133195(t *testing.T) {
|
||||||
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
|
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
|
||||||
testHookHostsPath = "testdata/hosts"
|
testHookHostsPath = "testdata/hosts"
|
||||||
|
|
||||||
_, err := r.LookupCNAME(context.Background(), "golang.org")
|
tests := []struct {
|
||||||
if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
|
name string
|
||||||
t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err, expected)
|
f func(*testing.T)
|
||||||
}
|
}{
|
||||||
_, err = LookupCNAME("golang.org")
|
{
|
||||||
if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
|
name: "CNAME",
|
||||||
t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err, expected)
|
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")
|
for _, tc := range tests {
|
||||||
if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
|
t.Run(tc.name, tc.f)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, 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) {
|
func TestNullMX(t *testing.T) {
|
||||||
|
|
|
@ -424,7 +424,7 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if !isDomainName(cname) {
|
if !isDomainName(cname) {
|
||||||
return "", &DNSError{Err: "CNAME target is invalid", Name: host}
|
return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host}
|
||||||
}
|
}
|
||||||
return cname, nil
|
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.
|
// and proto are empty strings, LookupSRV looks up name directly.
|
||||||
//
|
//
|
||||||
// The returned service names are validated to be properly
|
// 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) {
|
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)
|
||||||
}
|
}
|
||||||
|
@ -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.
|
// and proto are empty strings, LookupSRV looks up name directly.
|
||||||
//
|
//
|
||||||
// The returned service names are validated to be properly
|
// 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) {
|
func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
|
||||||
cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
|
cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -465,21 +469,28 @@ func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (
|
||||||
if cname != "" && !isDomainName(cname) {
|
if cname != "" && !isDomainName(cname) {
|
||||||
return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
|
return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
|
||||||
}
|
}
|
||||||
|
filteredAddrs := make([]*SRV, 0, len(addrs))
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !isDomainName(addr.Target) {
|
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.
|
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
|
||||||
//
|
//
|
||||||
// The returned mail server names are validated to be properly
|
// 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
|
// LookupMX uses context.Background internally; to specify the context, use
|
||||||
// Resolver.LookupMX.
|
// 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.
|
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
|
||||||
//
|
//
|
||||||
// The returned mail server names are validated to be properly
|
// 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) {
|
func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
|
||||||
records, err := r.lookupMX(ctx, name)
|
records, err := r.lookupMX(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
filteredMX := make([]*MX, 0, len(records))
|
||||||
for _, mx := range records {
|
for _, mx := range records {
|
||||||
if mx == nil {
|
if mx == nil {
|
||||||
continue
|
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,
|
// Bypass the hostname validity check for targets which contain only a dot,
|
||||||
// as this is used to represent a 'Null' MX record.
|
// as this is used to represent a 'Null' MX record.
|
||||||
if mx.Host != "." && !isDomainName(mx.Host) {
|
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.
|
// LookupNS returns the DNS NS records for the given domain name.
|
||||||
//
|
//
|
||||||
// The returned name server names are validated to be properly
|
// 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
|
// LookupNS uses context.Background internally; to specify the context, use
|
||||||
// Resolver.LookupNS.
|
// Resolver.LookupNS.
|
||||||
|
@ -523,21 +543,28 @@ func LookupNS(name string) ([]*NS, error) {
|
||||||
// LookupNS returns the DNS NS records for the given domain name.
|
// LookupNS returns the DNS NS records for the given domain name.
|
||||||
//
|
//
|
||||||
// The returned name server names are validated to be properly
|
// 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) {
|
func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
|
||||||
records, err := r.lookupNS(ctx, name)
|
records, err := r.lookupNS(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
filteredNS := make([]*NS, 0, len(records))
|
||||||
for _, ns := range records {
|
for _, ns := range records {
|
||||||
if ns == nil {
|
if ns == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !isDomainName(ns.Host) {
|
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.
|
// 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.
|
// of names mapping to that address.
|
||||||
//
|
//
|
||||||
// The returned names are validated to be properly formatted presentation-format
|
// 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
|
// When using the host C library resolver, at most one result will be
|
||||||
// returned. To bypass the host resolver, use a custom Resolver.
|
// 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.
|
// of names mapping to that address.
|
||||||
//
|
//
|
||||||
// The returned names are validated to be properly formatted presentation-format
|
// 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) {
|
func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
|
||||||
names, err := r.lookupAddr(ctx, addr)
|
names, err := r.lookupAddr(ctx, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
filteredNames := make([]string, 0, len(names))
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if !isDomainName(name) {
|
if isDomainName(name) {
|
||||||
return nil, &DNSError{Err: "PTR target is invalid", Name: addr}
|
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"
|
||||||
|
|
|
@ -229,7 +229,7 @@ type Type interface {
|
||||||
// See https://golang.org/issue/4876 for more details.
|
// 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.
|
* A few are known to ../runtime/type.go to convey to debuggers.
|
||||||
* They are also known to ../runtime/type.go.
|
* They are also known to ../runtime/type.go.
|
||||||
*/
|
*/
|
||||||
|
@ -272,7 +272,7 @@ const (
|
||||||
// available in the memory directly following the rtype value.
|
// available in the memory directly following the rtype value.
|
||||||
//
|
//
|
||||||
// tflag values must be kept in sync with copies in:
|
// 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
|
// cmd/link/internal/ld/decodesym.go
|
||||||
// runtime/type.go
|
// runtime/type.go
|
||||||
type tflag uint8
|
type tflag uint8
|
||||||
|
@ -1911,7 +1911,7 @@ func MapOf(key, elem Type) Type {
|
||||||
|
|
||||||
// Make a map type.
|
// Make a map type.
|
||||||
// Note: flag values must match those used in the TMAP case
|
// 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)
|
var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
|
||||||
mt := **(**mapType)(unsafe.Pointer(&imap))
|
mt := **(**mapType)(unsafe.Pointer(&imap))
|
||||||
mt.str = resolveReflectName(newName(s, "", false))
|
mt.str = resolveReflectName(newName(s, "", false))
|
||||||
|
@ -2842,7 +2842,7 @@ func runtimeStructField(field StructField) (structField, string) {
|
||||||
|
|
||||||
// typeptrdata returns the length in bytes of the prefix of t
|
// typeptrdata returns the length in bytes of the prefix of t
|
||||||
// containing pointer data. Anything after this offset is scalar data.
|
// 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 {
|
func typeptrdata(t *rtype) uintptr {
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case Struct:
|
case Struct:
|
||||||
|
@ -2866,7 +2866,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
|
const maxPtrmaskBytes = 2048
|
||||||
|
|
||||||
// ArrayOf returns the array type with the given length and element type.
|
// ArrayOf returns the array type with the given length and element type.
|
||||||
|
|
|
@ -895,7 +895,7 @@ type funcinl struct {
|
||||||
// layout of Itab known to compilers
|
// layout of Itab known to compilers
|
||||||
// allocated in non-garbage-collected memory
|
// allocated in non-garbage-collected memory
|
||||||
// Needs to be in sync with
|
// 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 {
|
type itab struct {
|
||||||
inter *interfacetype
|
inter *interfacetype
|
||||||
_type *_type
|
_type *_type
|
||||||
|
|
|
@ -16,7 +16,7 @@ const debugSelect = false
|
||||||
|
|
||||||
// Select case descriptor.
|
// Select case descriptor.
|
||||||
// Known to compiler.
|
// 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 {
|
type scase struct {
|
||||||
c *hchan // chan
|
c *hchan // chan
|
||||||
elem unsafe.Pointer // data element
|
elem unsafe.Pointer // data element
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
// tflag is documented in reflect/type.go.
|
// tflag is documented in reflect/type.go.
|
||||||
//
|
//
|
||||||
// tflag values must be kept in sync with copies in:
|
// 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
|
// cmd/link/internal/ld/decodesym.go
|
||||||
// reflect/type.go
|
// reflect/type.go
|
||||||
// internal/reflectlite/type.go
|
// internal/reflectlite/type.go
|
||||||
|
@ -28,7 +28,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize,
|
// 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.
|
// ../reflect/type.go:/^type.rtype.
|
||||||
// ../internal/reflectlite/type.go:/^type.rtype.
|
// ../internal/reflectlite/type.go:/^type.rtype.
|
||||||
type _type struct {
|
type _type struct {
|
||||||
|
@ -386,7 +386,7 @@ type maptype struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: flag values must match those used in the TMAP case
|
// 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
|
func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself
|
||||||
return mt.flags&1 != 0
|
return mt.flags&1 != 0
|
||||||
}
|
}
|
||||||
|
|
9
test/fixedbugs/issue47087.dir/a.go
Normal file
9
test/fixedbugs/issue47087.dir/a.go
Normal file
|
@ -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()
|
9
test/fixedbugs/issue47087.dir/b.go
Normal file
9
test/fixedbugs/issue47087.dir/b.go
Normal file
|
@ -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()
|
19
test/fixedbugs/issue47087.dir/main.go
Normal file
19
test/fixedbugs/issue47087.dir/main.go
Normal file
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
7
test/fixedbugs/issue47087.go
Normal file
7
test/fixedbugs/issue47087.go
Normal file
|
@ -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
|
Loading…
Reference in a new issue