doc/go1.6.html | 26 +++++++------------------- src/cmd/compile/internal/gc/parser.go | 18 ++++++++++++++++++ src/cmd/go/go_test.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/cmd/go/main.go | 9 +++++++++ src/cmd/go/pkg.go | 21 +++++++++++++++++++++ src/cmd/vet/print.go | 8 ++++---- src/cmd/vet/testdata/print.go | 3 +++ src/net/http/clientserver_test.go | 12 ++++++++---- src/net/http/h2_bundle.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++---- src/net/net_test.go | 24 ++++++++++++++++++++++-- src/os/doc.go | 6 +++++- src/runtime/cgo_mmap.go | 13 ++++++++++--- src/runtime/proc.go | 12 ++++++++++++ src/runtime/sys_darwin_386.s | 20 +++++++++++++------- src/unsafe/unsafe.go | 2 +- test/fixedbugs/issue14164.dir/a.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ test/fixedbugs/issue14164.dir/main.go | 12 ++++++++++++ test/fixedbugs/issue14164.go | 7 +++++++ diff --git a/doc/go1.6.html b/doc/go1.6.html index 46a8f65db3fd582732da0290401e63cfb989f51f..b4a3900aa088a6a797de63e7a916811057cc9bcc 100644 --- a/doc/go1.6.html +++ b/doc/go1.6.html @@ -464,20 +464,8 @@ Second, the new {{"{{"}}block}} action, combined with allowing redefinition of named templates, provides a simple way to define pieces of a template that can be replaced in different instantiations. -For example, the template -

- -
-<title>{{"{{"}}block "title"}}Page Title{{"{{"}}end}}</title>
-<body>
-<h1>{{"{{"}}template "title"}}</h1>
-{{"{{"}}block "page"}}Main text{{"{{"}}end}}
-
- -

-defines the basic formatting of a web page. A program can then -overlay that template with new definitions for the "title" -and "page" blocks to reuse the formatting for another page. +There is an example +in the text/template package that demonstrates this new feature.

Minor changes to the library

@@ -752,13 +740,13 @@ Client now allows user code to set the Expect: 100-continue header (see Transport.ExpectContinueTimeout). Fourth, there are -five new error codes from RFC 6585: +five new error codes: StatusPreconditionRequired (428), StatusTooManyRequests (429), -StatusRequestHeaderFieldsTooLarge (431), -StatusUnavailableForLegalReasons (451)), -and -StatusNetworkAuthenticationRequired (511). +StatusRequestHeaderFieldsTooLarge (431), and +StatusNetworkAuthenticationRequired (511) from RFC 6585, +as well as the recently-approved +StatusUnavailableForLegalReasons (451). Fifth, the implementation and documentation of CloseNotifier has been substantially changed. diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index 282e855b37eacf4ba16c0c7a1d8917f0c19ef947..054cf7365617ce662a5b9b244c1c751900f95a0d 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -2501,6 +2501,24 @@ meth := Nod(ODCLFIELD, mname, sig) ifacedcl(meth) return meth + case '@', '?': + // newname indcl + // We arrive here when parsing an interface type declared inside + // an exported and inlineable function and the interface declares + // unexported methods (which are then package-qualified). + // + // Since the compiler always flattens embedded interfaces, we + // will never see an embedded package-qualified interface in export + // data; i.e., when we reach here we know it must be a method. + // + // See also issue 14164. + mname := newname(p.sym()) + sig := p.indcl() + + meth := Nod(ODCLFIELD, mname, sig) + ifacedcl(meth) + return meth + case '(': p.next() pname := p.packname(nil) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index a901ca8666cfcf5a6ea7ade308309588a1a949a1..0136ba4b1b1c3bdd523e019e4cd4a77074380a11 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -1621,7 +1621,7 @@ tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test") } // Issue 4568. -func TestSymlinksDoNotConfuseGoList(t *testing.T) { +func TestSymlinksList(t *testing.T) { switch runtime.GOOS { case "plan9", "windows": t.Skipf("skipping symlink test on %s", runtime.GOOS) @@ -1638,6 +1638,58 @@ tg.run("list", "-f", "{{.Root}}", "dir1") if strings.TrimSpace(tg.getStdout()) != tg.path(".") { t.Error("confused by symlinks") } +} + +// Issue 14054. +func TestSymlinksVendor(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("skipping symlink test on %s", runtime.GOOS) + } + + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GO15VENDOREXPERIMENT", "1") + tg.tempDir("gopath/src/dir1/vendor/v") + tg.tempFile("gopath/src/dir1/p.go", "package main\nimport _ `v`\nfunc main(){}") + tg.tempFile("gopath/src/dir1/vendor/v/v.go", "package v") + tg.must(os.Symlink(tg.path("gopath/src/dir1"), tg.path("symdir1"))) + tg.setenv("GOPATH", tg.path("gopath")) + tg.cd(tg.path("symdir1")) + tg.run("list", "-f", "{{.Root}}", ".") + if strings.TrimSpace(tg.getStdout()) != tg.path("gopath") { + t.Error("list confused by symlinks") + } + + // All of these should succeed, not die in vendor-handling code. + tg.run("run", "p.go") + tg.run("build") + tg.run("install") +} + +func TestSymlinksInternal(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("skipping symlink test on %s", runtime.GOOS) + } + + tg := testgo(t) + defer tg.cleanup() + tg.tempDir("gopath/src/dir1/internal/v") + tg.tempFile("gopath/src/dir1/p.go", "package main\nimport _ `dir1/internal/v`\nfunc main(){}") + tg.tempFile("gopath/src/dir1/internal/v/v.go", "package v") + tg.must(os.Symlink(tg.path("gopath/src/dir1"), tg.path("symdir1"))) + tg.setenv("GOPATH", tg.path("gopath")) + tg.cd(tg.path("symdir1")) + tg.run("list", "-f", "{{.Root}}", ".") + if strings.TrimSpace(tg.getStdout()) != tg.path("gopath") { + t.Error("list confused by symlinks") + } + + // All of these should succeed, not die in internal-handling code. + tg.run("run", "p.go") + tg.run("build") + tg.run("install") } // Issue 4515. diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index c8697ffe98ca3c636606992e27672703d51e1599..d384594722511028a25ea87d21279a35c72e7468 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -524,6 +524,15 @@ return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix } } +// expandPath returns the symlink-expanded form of path. +func expandPath(p string) string { + x, err := filepath.EvalSymlinks(p) + if err == nil { + return x + } + return p +} + // treeCanMatchPattern(pattern)(name) reports whether // name or children of name can possibly match pattern. // Pattern is the same limited glob accepted by matchPattern. diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index 112f820d802fcfd11d0ba7288382ad98095317a2..95a06ffedcd8b7deced2782677f0fb031bd08b87 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -415,11 +415,18 @@ func vendoredImportPath(parent *Package, path string) (found string) { if parent == nil || parent.Root == "" || !go15VendorExperiment { return path } + dir := filepath.Clean(parent.Dir) root := filepath.Join(parent.Root, "src") + if !hasFilePathPrefix(dir, root) { + // Look for symlinks before reporting error. + dir = expandPath(dir) + root = expandPath(root) + } if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator { fatalf("invalid vendoredImportPath: dir=%q root=%q separator=%q", dir, root, string(filepath.Separator)) } + vpath := "vendor/" + path for i := len(dir); i >= len(root); i-- { if i < len(dir) && dir[i] != filepath.Separator { @@ -533,6 +540,13 @@ if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { return p } + // Look for symlinks before reporting error. + srcDir = expandPath(srcDir) + parent = expandPath(parent) + if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { + return p + } + // Internal is present, and srcDir is outside parent's tree. Not allowed. perr := *p perr.Error = &PackageError{ @@ -626,6 +640,13 @@ if truncateTo < 0 || len(p.Dir) < truncateTo { return p } parent := p.Dir[:truncateTo] + if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { + return p + } + + // Look for symlinks before reporting error. + srcDir = expandPath(srcDir) + parent = expandPath(parent) if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { return p } diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go index 5436c5bf04b5b486a2e94322ea25201c713158c6..a16e864cad212df7fc5480b736037c6d448e7fda 100644 --- a/src/cmd/vet/print.go +++ b/src/cmd/vet/print.go @@ -445,12 +445,12 @@ if !f.argCanBeChecked(call, len(state.argNums)-1, false, state) { return false } arg := call.Args[argNum] + if f.isFunctionValue(arg) && state.verb != 'p' && state.verb != 'T' { + f.Badf(call.Pos(), "arg %s in printf call is a function value, not a function call", f.gofmt(arg)) + return false + } if !f.matchArgType(v.typ, nil, arg) { typeString := "" - if f.isFunctionValue(arg) { - f.Badf(call.Pos(), "arg %s in printf call is a function value, not a function call", f.gofmt(arg)) - return false - } if typ := f.pkg.types[arg].Type; typ != nil { typeString = typ.String() } diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go index beeb642f2ad19dbf07c6f393d4bc922501df1b60..c5faa36e897a957d57e237b4fea8113ecdc89382 100644 --- a/src/cmd/vet/testdata/print.go +++ b/src/cmd/vet/testdata/print.go @@ -197,7 +197,10 @@ var et5 errorTest5 et5.error() // ok, not an error method. // Can't print a function. Printf("%d", someFunction) // ERROR "arg someFunction in printf call is a function value, not a function call" + Printf("%v", someFunction) // ERROR "arg someFunction in printf call is a function value, not a function call" Println(someFunction) // ERROR "arg someFunction in Println call is a function value, not a function call" + Printf("%p", someFunction) // ok: maybe someone wants to see the pointer + Printf("%T", someFunction) // ok: maybe someone wants to see the type // Bug: used to recur forever. Printf("%p %x", recursiveStructV, recursiveStructV.next) Printf("%p %x", recursiveStruct1V, recursiveStruct1V.next) diff --git a/src/net/http/clientserver_test.go b/src/net/http/clientserver_test.go index 9b581e73117cc4caf06e6777a722e2dcb4525ae6..fbaa805712b157a50d35c7c9ae99694ae97e8949 100644 --- a/src/net/http/clientserver_test.go +++ b/src/net/http/clientserver_test.go @@ -1001,13 +1001,17 @@ t.Errorf("%d connections opened, %d closed; want %d to close", open, close, open-1) } // tests that Transport doesn't retain a pointer to the provided request. -func TestTransportGCRequest_h1(t *testing.T) { testTransportGCRequest(t, h1Mode) } -func TestTransportGCRequest_h2(t *testing.T) { testTransportGCRequest(t, h2Mode) } -func testTransportGCRequest(t *testing.T, h2 bool) { +func TestTransportGCRequest_Body_h1(t *testing.T) { testTransportGCRequest(t, h1Mode, true) } +func TestTransportGCRequest_Body_h2(t *testing.T) { testTransportGCRequest(t, h2Mode, true) } +func TestTransportGCRequest_NoBody_h1(t *testing.T) { testTransportGCRequest(t, h1Mode, false) } +func TestTransportGCRequest_NoBody_h2(t *testing.T) { testTransportGCRequest(t, h2Mode, false) } +func testTransportGCRequest(t *testing.T, h2, body bool) { defer afterTest(t) cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { ioutil.ReadAll(r.Body) - io.WriteString(w, "Hello.") + if body { + io.WriteString(w, "Hello.") + } })) defer cst.close() diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index e7236299e2253d824739005e97a8b52043a5107e..11f33cf3b18d9206d374d4c9c71e13171d8376be 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -2851,8 +2851,6 @@ log.Printf(format, args...) } } -var http2uintptrType = reflect.TypeOf(uintptr(0)) - // errno returns v's underlying uintptr, else 0. // // TODO: remove this helper function once http2 can use build @@ -4220,7 +4218,9 @@ case "Transfer-Encoding", "Content-Length", "Trailer": return } - rws.trailers = append(rws.trailers, k) + if !http2strSliceContains(rws.trailers, k) { + rws.trailers = append(rws.trailers, k) + } } // writeChunk writes chunks from the bufio.Writer. But because @@ -4288,6 +4288,10 @@ if len(p) == 0 && !rws.handlerDone { return 0, nil } + if rws.handlerDone { + rws.promoteUndeclaredTrailers() + } + endStream := rws.handlerDone && !rws.hasTrailers() if len(p) > 0 || endStream { @@ -4308,6 +4312,53 @@ } return len(p), nil } +// TrailerPrefix is a magic prefix for ResponseWriter.Header map keys +// that, if present, signals that the map entry is actually for +// the response trailers, and not the response headers. The prefix +// is stripped after the ServeHTTP call finishes and the values are +// sent in the trailers. +// +// This mechanism is intended only for trailers that are not known +// prior to the headers being written. If the set of trailers is fixed +// or known before the header is written, the normal Go trailers mechanism +// is preferred: +// https://golang.org/pkg/net/http/#ResponseWriter +// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers +const http2TrailerPrefix = "Trailer:" + +// promoteUndeclaredTrailers permits http.Handlers to set trailers +// after the header has already been flushed. Because the Go +// ResponseWriter interface has no way to set Trailers (only the +// Header), and because we didn't want to expand the ResponseWriter +// interface, and because nobody used trailers, and because RFC 2616 +// says you SHOULD (but not must) predeclare any trailers in the +// header, the official ResponseWriter rules said trailers in Go must +// be predeclared, and then we reuse the same ResponseWriter.Header() +// map to mean both Headers and Trailers. When it's time to write the +// Trailers, we pick out the fields of Headers that were declared as +// trailers. That worked for a while, until we found the first major +// user of Trailers in the wild: gRPC (using them only over http2), +// and gRPC libraries permit setting trailers mid-stream without +// predeclarnig them. So: change of plans. We still permit the old +// way, but we also permit this hack: if a Header() key begins with +// "Trailer:", the suffix of that key is a Trailer. Because ':' is an +// invalid token byte anyway, there is no ambiguity. (And it's already +// filtered out) It's mildly hacky, but not terrible. +// +// This method runs after the Handler is done and promotes any Header +// fields to be trailers. +func (rws *http2responseWriterState) promoteUndeclaredTrailers() { + for k, vv := range rws.handlerHeader { + if !strings.HasPrefix(k, http2TrailerPrefix) { + continue + } + trailerKey := strings.TrimPrefix(k, http2TrailerPrefix) + rws.declareTrailer(trailerKey) + rws.handlerHeader[CanonicalHeaderKey(trailerKey)] = vv + } + sort.Strings(rws.trailers) +} + func (w *http2responseWriter) Flush() { rws := w.rws if rws == nil { @@ -5611,10 +5662,10 @@ res.Header.Del("Content-Length") res.ContentLength = -1 res.Body = &http2gzipReader{body: res.Body} } + rl.activeRes[cs.ID] = cs } cs.resTrailer = &res.Trailer - rl.activeRes[cs.ID] = cs cs.resc <- http2resAndError{res: res} rl.nextRes = nil return nil @@ -6258,8 +6309,16 @@ } for _, k := range keys { vv := h[k] k = http2lowerHeader(k) + if !http2validHeaderFieldName(k) { + + continue + } isTE := k == "transfer-encoding" for _, v := range vv { + if !http2validHeaderFieldValue(v) { + + continue + } if isTE && v != "trailers" { continue diff --git a/src/net/net_test.go b/src/net/net_test.go index 6dcfc2190e03c5675a75d5952f7a5fcefbe9fbcf..cd62b4373ebb1aafc66728432e19d808ba32672c 100644 --- a/src/net/net_test.go +++ b/src/net/net_test.go @@ -9,6 +9,7 @@ "io" "os" "runtime" "testing" + "time" ) func TestCloseRead(t *testing.T) { @@ -209,6 +210,7 @@ case "unix", "unixpacket": defer os.Remove(ln.Addr().String()) } + dst := ln.Addr().String() if err := ln.Close(); err != nil { if perr := parseCloseError(err); perr != nil { t.Error(perr) @@ -222,9 +224,24 @@ t.Fatal("should fail") } if network == "tcp" { - cc, err := Dial("tcp", ln.Addr().String()) + // We will have two TCP FSMs inside the + // kernel here. There's no guarantee that a + // signal comes from the far end FSM will be + // delivered immediately to the near end FSM, + // especially on the platforms that allow + // multiple consumer threads to pull pending + // established connections at the same time by + // enabling SO_REUSEPORT option such as Linux, + // DragonFly BSD. So we need to give some time + // quantum to the kernel. + // + // Note that net.inet.tcp.reuseport_ext=1 by + // default on DragonFly BSD. + time.Sleep(time.Millisecond) + + cc, err := Dial("tcp", dst) if err == nil { - t.Error("Dial to closed TCP listener succeeeded.") + t.Error("Dial to closed TCP listener succeeded.") cc.Close() } } @@ -272,6 +289,9 @@ t.Fatal(err) } addr := ln.Addr().String() if err := ln.Close(); err != nil { + if perr := parseCloseError(err); perr != nil { + t.Error(perr) + } t.Fatal(err) } ln, err = Listen("tcp", addr) diff --git a/src/os/doc.go b/src/os/doc.go index 389a8eb14cb284db9a5190fda7dda7ab604ac2ed..869a28a8a4e56d1e34df58567ac17846e888b9f9 100644 --- a/src/os/doc.go +++ b/src/os/doc.go @@ -7,9 +7,13 @@ import "time" // FindProcess looks for a running process by its pid. +// // The Process it returns can be used to obtain information // about the underlying operating system process. -func FindProcess(pid int) (p *Process, err error) { +// +// On Unix systems, FindProcess always succeeds and returns a Process +// for the given pid, regardless of whether the process exists. +func FindProcess(pid int) (*Process, error) { return findProcess(pid) } diff --git a/src/runtime/cgo_mmap.go b/src/runtime/cgo_mmap.go index ef5501ca5f7ad5ea3d93c341400ff10b62eda8e9..c0396bdde51b84ad4eecd410345d84bd2b4e47e9 100644 --- a/src/runtime/cgo_mmap.go +++ b/src/runtime/cgo_mmap.go @@ -15,12 +15,19 @@ // program, so it is only non-nil when using cgo. //go:linkname _cgo_mmap _cgo_mmap var _cgo_mmap unsafe.Pointer -func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (ret unsafe.Pointer) { +func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer { if _cgo_mmap != nil { + // Make ret a uintptr so that writing to it in the + // function literal does not trigger a write barrier. + // A write barrier here could break because of the way + // that mmap uses the same value both as a pointer and + // an errno value. + // TODO: Fix mmap to return two values. + var ret uintptr systemstack(func() { ret = callCgoMmap(addr, n, prot, flags, fd, off) }) - return + return unsafe.Pointer(ret) } return sysMmap(addr, n, prot, flags, fd, off) } @@ -31,4 +38,4 @@ // cgoMmap calls the mmap function in the runtime/cgo package on the // callCgoMmap calls the mmap function in the runtime/cgo package // using the GCC calling convention. It is implemented in assembly. -func callCgoMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer +func callCgoMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) uintptr diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 2bc3c920dc6fda5f36c0096f585eca470fa8db08..d1f5088b5029bef85c0380c0dd068e13bbb8df2e 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -1602,8 +1602,16 @@ // Hands off P from syscall or locked M. // Always runs without a P, so write barriers are not allowed. //go:nowritebarrier func handoffp(_p_ *p) { + // handoffp must start an M in any situation where + // findrunnable would return a G to run on _p_. + // if it has local work, start it straight away if !runqempty(_p_) || sched.runqsize != 0 { + startm(_p_, false) + return + } + // if it has GC work, start it straight away + if gcBlackenEnabled != 0 && gcMarkWorkAvailable(_p_) { startm(_p_, false) return } @@ -1786,6 +1794,10 @@ // Finds a runnable goroutine to execute. // Tries to steal from other P's, get g from global queue, poll network. func findrunnable() (gp *g, inheritTime bool) { _g_ := getg() + + // The conditions here and in handoffp must agree: if + // findrunnable would return a G to run, handoffp must start + // an M. top: if sched.gcwaiting != 0 { diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s index c516ef2da81a8195be1d10d37a0f1d93c9465ab0..ad3dca444a830cf0028b07473e1cb7b80bf8eeb1 100644 --- a/src/runtime/sys_darwin_386.s +++ b/src/runtime/sys_darwin_386.s @@ -242,15 +242,21 @@ JAE 2(PC) MOVL $0xf1, 0xf1 // crash RET -TEXT runtime·sigfwd(SB),NOSPLIT,$12-16 - MOVL sig+4(FP), AX - MOVL AX, 0(SP) - MOVL info+8(FP), AX - MOVL AX, 4(SP) - MOVL ctx+12(FP), AX - MOVL AX, 8(SP) +TEXT runtime·sigfwd(SB),NOSPLIT,$0-16 MOVL fn+0(FP), AX + MOVL sig+4(FP), BX + MOVL info+8(FP), CX + MOVL ctx+12(FP), DX + MOVL SP, SI + SUBL $32, SP // align stack; handler might be C code + ANDL $~15, SP + MOVL BX, 0(SP) + MOVL CX, 4(SP) + MOVL DX, 8(SP) + MOVL SI, 12(SP) CALL AX + MOVL 12(SP), AX + MOVL AX, SP RET TEXT runtime·sigreturn(SB),NOSPLIT,$12-8 diff --git a/src/unsafe/unsafe.go b/src/unsafe/unsafe.go index 33b31142192971272cd5d571f8612f624dd6b88e..532fa4aa2294560f95d6df0631dceb47ed612920 100644 --- a/src/unsafe/unsafe.go +++ b/src/unsafe/unsafe.go @@ -63,7 +63,7 @@ // // (3) Conversion of a Pointer to a uintptr and back, with arithmetic. // // If p points into an allocated object, it can be advanced through the object -// by conversion to uintptr, addition of an offset, and conversion back to uintptr. +// by conversion to uintptr, addition of an offset, and conversion back to Pointer. // // p = unsafe.Pointer(uintptr(p) + offset) // diff --git a/test/fixedbugs/issue14164.dir/a.go b/test/fixedbugs/issue14164.dir/a.go new file mode 100644 index 0000000000000000000000000000000000000000..bf03051619817a7f5f421d99d467a9eea6f95b64 --- /dev/null +++ b/test/fixedbugs/issue14164.dir/a.go @@ -0,0 +1,47 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +// F is an exported function, small enough to be inlined. +// It defines a local interface with an unexported method +// f, which will appear with a package-qualified method +// name in the export data. +func F(x interface{}) bool { + _, ok := x.(interface { + f() + }) + return ok +} + +// Like F but with the unexported interface method f +// defined via an embedded interface t. The compiler +// always flattens embedded interfaces so there should +// be no difference between F and G. Alas, currently +// G is not inlineable (at least via export data), so +// the issue is moot, here. +func G(x interface{}) bool { + type t0 interface { + f() + } + _, ok := x.(interface { + t0 + }) + return ok +} + +// Like G but now the embedded interface is declared +// at package level. This function is inlineable via +// export data. The export data representation is like +// for F. +func H(x interface{}) bool { + _, ok := x.(interface { + t1 + }) + return ok +} + +type t1 interface { + f() +} diff --git a/test/fixedbugs/issue14164.dir/main.go b/test/fixedbugs/issue14164.dir/main.go new file mode 100644 index 0000000000000000000000000000000000000000..bcc6a63c2071588a0bf6da9fd2c868e0877f7a62 --- /dev/null +++ b/test/fixedbugs/issue14164.dir/main.go @@ -0,0 +1,12 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// Verify that we can import package "a" containing an inlineable +// function F that declares a local interface with a non-exported +// method f. +import _ "./a" + +func main() {} diff --git a/test/fixedbugs/issue14164.go b/test/fixedbugs/issue14164.go new file mode 100644 index 0000000000000000000000000000000000000000..5247599d497baf21f6e17ac75df9520f18fb6d6e --- /dev/null +++ b/test/fixedbugs/issue14164.go @@ -0,0 +1,7 @@ +// compiledir + +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +ignored