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.
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