From patchwork Mon Apr 17 22:11:07 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 751579 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3w6MtN514Mz9s73 for ; Tue, 18 Apr 2017 08:11:39 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="oSG6y3xk"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=FDGI3e3p7AWURnzJ+IJKqLxN+goAN6uuiX6pgMmp3gHqjM 1by7pi3T7OOyV9CKtNn2w18EsqLQTvNM38Z5Hue2bZG5o2vLXCcoxQ/cZBlXR/Kg RMS/L7GtcuuW+VWvXuXpgwMmT7sfuRU/g3QLs6aYDAh6K5sK2965qtX4H6GzQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=isg9JmDepAxabOJX7GSwV9kEA6Y=; b=oSG6y3xkALPn+laIaVS/ cvYhnYy+0zVt/PohPBklnC8RYAVCt3mkup/gSHHN7zU5v2dWMnlSr3ga6clbILo6 Me2wIyDb/anp6x3d7Kqf7m0UQlnFU30S5Ps7aY9jTB+T2kxtkkcdyZjyoMeYgMPw MwF/l1ZyNi1AwxnNEsIc64g= Received: (qmail 26541 invoked by alias); 17 Apr 2017 22:11:19 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 18821 invoked by uid 89); 17 Apr 2017 22:11:12 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-13.1 required=5.0 tests=AWL, BAYES_20, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=UD:do, actions, 275, tot X-HELO: mail-oi0-f51.google.com Received: from mail-oi0-f51.google.com (HELO mail-oi0-f51.google.com) (209.85.218.51) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 17 Apr 2017 22:11:08 +0000 Received: by mail-oi0-f51.google.com with SMTP id j201so4663638oih.2 for ; Mon, 17 Apr 2017 15:11:09 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=lBb45LhhtgwsJcbthgFLhP8oVpWxBrQ0bJ8LSMKHC3c=; b=WoGgs8T+FXQfaSE0Ij0OpMhXlKfgEabhcKoC6tk7Yv5yadHamd2xCMmMT60H+cOej1 YIkWbXrDcP1NS6RXkBlHcliODEkjWyfOuiQflBYINw1mYMCfjUpjyPL3lhdhkWgW3RYx l0ZUTrX6TcOhYZz47OJ/jG409VGuF5RbGuelMX2nEJpCKu6VQoR7dFUcqaKA/OOMkhwg i8b+JJUPsYe2pIbwUKYGFmIWxC29bg/i68Qxj9fb8qsmKY0/DMekR5pyne7RhuAPqXf+ +hQoZBf6fCJt7GdoRZfvTmMWEQnXOOhccoaw9LGgFU5q2kxUn30HVspsyfVpeCyVXbhc pZvw== X-Gm-Message-State: AN3rC/4jz0X1BVSKAl3Yq6ubz/GVXvZdAjObZH0uErDCdjlmwki31Li/ sfz7id/TiMi/Y6iz5L/Oa5pbWR7t7A== X-Received: by 10.157.46.16 with SMTP id q16mr5667313otb.102.1492467068258; Mon, 17 Apr 2017 15:11:08 -0700 (PDT) MIME-Version: 1.0 Received: by 10.202.44.140 with HTTP; Mon, 17 Apr 2017 15:11:07 -0700 (PDT) From: Ian Lance Taylor Date: Mon, 17 Apr 2017 15:11:07 -0700 Message-ID: Subject: libgo: update to Go 1.8.1 To: gcc-patches , "gofrontend-dev@googlegroups.com" This patch to libgo updates it to the Go 1.8.1 release. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian Index: libgo/MERGE =================================================================== --- libgo/MERGE (revision 246951) +++ libgo/MERGE (working copy) @@ -1,4 +1,4 @@ -cd6b6202dd1559b3ac63179b45f1833fcfbe7eca +a4c18f063b6659079ca2848ca217a0587dabc001 The first line of this file holds the git revision number of the last merge done from the master library sources. Index: libgo/VERSION =================================================================== --- libgo/VERSION (revision 246951) +++ libgo/VERSION (working copy) @@ -1 +1 @@ -go1.8 +go1.8.1 Index: libgo/go/cmd/go/go_test.go =================================================================== --- libgo/go/cmd/go/go_test.go (revision 246951) +++ libgo/go/cmd/go/go_test.go (working copy) @@ -2227,6 +2227,24 @@ } } +func TestTestRaceInstall(t *testing.T) { + if !canRace { + t.Skip("no race detector") + } + + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + + tg.tempDir("pkg") + pkgdir := tg.path("pkg") + tg.run("install", "-race", "-pkgdir="+pkgdir, "std") + tg.run("test", "-race", "-pkgdir="+pkgdir, "-i", "-v", "empty/pkg") + if tg.getStderr() != "" { + t.Error("go test -i -race: rebuilds cached packages") + } +} + func TestBuildDryRunWithCgo(t *testing.T) { if !canCgo { t.Skip("skipping because cgo not enabled") Index: libgo/go/cmd/go/pkg.go =================================================================== --- libgo/go/cmd/go/pkg.go (revision 246951) +++ libgo/go/cmd/go/pkg.go (working copy) @@ -970,10 +970,6 @@ if p.Name == "main" && goarch == "arm" { importPaths = append(importPaths, "math") } - // In coverage atomic mode everything depends on sync/atomic. - if testCoverMode == "atomic" && (!p.Standard || (p.ImportPath != "runtime/cgo" && p.ImportPath != "runtime/race" && p.ImportPath != "sync/atomic")) { - importPaths = append(importPaths, "sync/atomic") - } } // Runtime and its internal packages depend on runtime/internal/sys, Index: libgo/go/cmd/go/test.go =================================================================== --- libgo/go/cmd/go/test.go (revision 246951) +++ libgo/go/cmd/go/test.go (working copy) @@ -548,6 +548,10 @@ // Prepare build + run + print actions for all packages being tested. for _, p := range pkgs { + // sync/atomic import is inserted by the cover tool. See #18486 + if testCover && testCoverMode == "atomic" { + ensureImport(p, "sync/atomic") + } buildTest, runTest, printTest, err := b.test(p) if err != nil { str := err.Error() @@ -639,6 +643,23 @@ b.do(root) } +// ensures that package p imports the named package. +func ensureImport(p *Package, pkg string) { + for _, d := range p.deps { + if d.Name == pkg { + return + } + } + + a := loadPackage(pkg, &importStack{}) + if a.Error != nil { + fatalf("load %s: %v", pkg, a.Error) + } + computeStale(a) + + p.imports = append(p.imports, a) +} + func contains(x []string, s string) bool { for _, t := range x { if t == s { Index: libgo/go/crypto/tls/common.go =================================================================== --- libgo/go/crypto/tls/common.go (revision 246951) +++ libgo/go/crypto/tls/common.go (working copy) @@ -563,6 +563,7 @@ Certificates: c.Certificates, NameToCertificate: c.NameToCertificate, GetCertificate: c.GetCertificate, + GetClientCertificate: c.GetClientCertificate, GetConfigForClient: c.GetConfigForClient, VerifyPeerCertificate: c.VerifyPeerCertificate, RootCAs: c.RootCAs, Index: libgo/go/crypto/tls/tls_test.go =================================================================== --- libgo/go/crypto/tls/tls_test.go (revision 246951) +++ libgo/go/crypto/tls/tls_test.go (working copy) @@ -13,13 +13,11 @@ "io" "io/ioutil" "math" - "math/rand" "net" "os" "reflect" "strings" "testing" - "testing/quick" "time" ) @@ -568,11 +566,50 @@ } } -func TestClone(t *testing.T) { +func TestCloneFuncFields(t *testing.T) { + const expectedCount = 5 + called := 0 + + c1 := Config{ + Time: func() time.Time { + called |= 1 << 0 + return time.Time{} + }, + GetCertificate: func(*ClientHelloInfo) (*Certificate, error) { + called |= 1 << 1 + return nil, nil + }, + GetClientCertificate: func(*CertificateRequestInfo) (*Certificate, error) { + called |= 1 << 2 + return nil, nil + }, + GetConfigForClient: func(*ClientHelloInfo) (*Config, error) { + called |= 1 << 3 + return nil, nil + }, + VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + called |= 1 << 4 + return nil + }, + } + + c2 := c1.Clone() + + c2.Time() + c2.GetCertificate(nil) + c2.GetClientCertificate(nil) + c2.GetConfigForClient(nil) + c2.VerifyPeerCertificate(nil, nil) + + if called != (1<`, true}, + {``, true}, + {``, true}, + {``, true}, + {``, false}, + {``, false}, + {`bad`, false}, + } + + for _, tt := range tests { + err := Unmarshal([]byte(tt.input), new(X)) + if tt.ok { + if err != nil { + t.Errorf("%s: unexpected error: %v", tt.input, err) + } + } else { + if err == nil { + t.Errorf("%s: unexpected success", tt.input) + } + } + } +} Index: libgo/go/image/png/reader.go =================================================================== --- libgo/go/image/png/reader.go (revision 246951) +++ libgo/go/image/png/reader.go (working copy) @@ -612,6 +612,11 @@ } } case cbG8: + if d.useTransparent { + // Match error from Go 1.7 and earlier. + // Go 1.9 will decode this properly. + return nil, chunkOrderError + } copy(gray.Pix[pixOffset:], cdat) pixOffset += gray.Stride case cbGA8: Index: libgo/go/image/png/reader_test.go =================================================================== --- libgo/go/image/png/reader_test.go (revision 246951) +++ libgo/go/image/png/reader_test.go (working copy) @@ -629,3 +629,13 @@ func BenchmarkDecodeInterlacing(b *testing.B) { benchmarkDecode(b, "testdata/benchRGB-interlace.png", 4) } + +func TestIssue19553(t *testing.T) { + var buf = []byte{ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x85, 0x2c, 0x88, 0x80, 0x00, 0x00, 0x00, 0x02, 0x74, 0x52, 0x4e, 0x53, 0x00, 0xff, 0x5b, 0x91, 0x22, 0xb5, 0x00, 0x00, 0x00, 0x02, 0x62, 0x4b, 0x47, 0x44, 0x00, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0a, 0xf0, 0x00, 0x00, 0x0a, 0xf0, 0x01, 0x42, 0xac, 0x34, 0x98, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xd5, 0x04, 0x02, 0x12, 0x11, 0x11, 0xf7, 0x65, 0x3d, 0x8b, 0x00, 0x00, 0x00, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xff, 0xff, 0xff, 0xb9, 0xbd, 0x70, 0xf0, 0x8c, 0x01, 0xc8, 0xaf, 0x6e, 0x99, 0x02, 0x05, 0xd9, 0x7b, 0xc1, 0xfc, 0x6b, 0xff, 0xa1, 0xa0, 0x87, 0x30, 0xff, 0xd9, 0xde, 0xbd, 0xd5, 0x4b, 0xf7, 0xee, 0xfd, 0x0e, 0xe3, 0xef, 0xcd, 0x06, 0x19, 0x14, 0xf5, 0x1e, 0xce, 0xef, 0x01, 0x31, 0x92, 0xd7, 0x82, 0x41, 0x31, 0x9c, 0x3f, 0x07, 0x02, 0xee, 0xa1, 0xaa, 0xff, 0xff, 0x9f, 0xe1, 0xd9, 0x56, 0x30, 0xf8, 0x0e, 0xe5, 0x03, 0x00, 0xa9, 0x42, 0x84, 0x3d, 0xdf, 0x8f, 0xa6, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, + } + _, err := Decode(bytes.NewReader(buf)) + if err != chunkOrderError { + t.Errorf("Decode: expected chunkOrderError for transparent gray8, got %v", err) + } +} Index: libgo/go/internal/testenv/testenv.go =================================================================== --- libgo/go/internal/testenv/testenv.go (revision 246951) +++ libgo/go/internal/testenv/testenv.go (working copy) @@ -141,6 +141,15 @@ } } +var haveCGO bool + +// MustHaveCGO calls t.Skip if cgo is not available. +func MustHaveCGO(t *testing.T) { + if !haveCGO { + t.Skipf("skipping test: no cgo") + } +} + // HasSymlink reports whether the current system can use os.Symlink. func HasSymlink() bool { ok, _ := hasSymlink() Index: libgo/go/internal/testenv/testenv_cgo.go =================================================================== --- libgo/go/internal/testenv/testenv_cgo.go (revision 0) +++ libgo/go/internal/testenv/testenv_cgo.go (working copy) @@ -0,0 +1,11 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo + +package testenv + +func init() { + haveCGO = true +} Index: libgo/go/net/http/http.go =================================================================== --- libgo/go/net/http/http.go (revision 246951) +++ libgo/go/net/http/http.go (working copy) @@ -20,7 +20,7 @@ // aLongTimeAgo is a non-zero time, far in the past, used for // immediate cancelation of network operations. -var aLongTimeAgo = time.Unix(233431200, 0) +var aLongTimeAgo = time.Unix(1, 0) // TODO(bradfitz): move common stuff here. The other files have accumulated // generic http stuff in random places. Index: libgo/go/net/net.go =================================================================== --- libgo/go/net/net.go (revision 246951) +++ libgo/go/net/net.go (working copy) @@ -468,7 +468,7 @@ var ( // aLongTimeAgo is a non-zero time, far in the past, used for // immediate cancelation of dials. - aLongTimeAgo = time.Unix(233431200, 0) + aLongTimeAgo = time.Unix(1, 0) // nonDeadline and noCancel are just zero values for // readability with functions taking too many parameters. Index: libgo/go/os/exec/exec_test.go =================================================================== --- libgo/go/os/exec/exec_test.go (revision 246951) +++ libgo/go/os/exec/exec_test.go (working copy) @@ -266,9 +266,13 @@ t.Fatalf("Start: %v", err) } go func() { - if err := cmd.Process.Kill(); err != nil { - t.Errorf("Kill: %v", err) - } + // We don't check the error return of Kill. It is + // possible that the process has already exited, in + // which case Kill will return an error "process + // already finished". The purpose of this test is to + // see whether the race detector reports an error; it + // doesn't matter whether this Kill succeeds or not. + cmd.Process.Kill() }() go func() { // Send the wrong string, so that the child fails even Index: libgo/go/reflect/all_test.go =================================================================== --- libgo/go/reflect/all_test.go (revision 246951) +++ libgo/go/reflect/all_test.go (working copy) @@ -1681,6 +1681,11 @@ } // This will be index 3. +func (p Point) NoArgs() { + // Exercise no-argument/no-result paths. +} + +// This will be index 4. func (p Point) TotalDist(points ...Point) int { tot := 0 for _, q := range points { @@ -1709,6 +1714,15 @@ t.Errorf("Type MethodByName returned %d; want 275", i) } + m, ok = TypeOf(p).MethodByName("NoArgs") + if !ok { + t.Fatalf("method by name failed") + } + n := len(m.Func.Call([]Value{ValueOf(p)})) + if n != 0 { + t.Errorf("NoArgs returned %d values; want 0", n) + } + i = TypeOf(&p).Method(1).Func.Call([]Value{ValueOf(&p), ValueOf(12)})[0].Int() if i != 300 { t.Errorf("Pointer Type Method returned %d; want 300", i) @@ -1723,6 +1737,15 @@ t.Errorf("Pointer Type MethodByName returned %d; want 325", i) } + m, ok = TypeOf(&p).MethodByName("NoArgs") + if !ok { + t.Fatalf("method by name failed") + } + n = len(m.Func.Call([]Value{ValueOf(&p)})) + if n != 0 { + t.Errorf("NoArgs returned %d values; want 0", n) + } + // Curried method of value. tfunc := TypeOf((func(int) int)(nil)) v := ValueOf(p).Method(1) @@ -1741,6 +1764,8 @@ if i != 375 { t.Errorf("Value MethodByName returned %d; want 375", i) } + v = ValueOf(p).MethodByName("NoArgs") + v.Call(nil) // Curried method of pointer. v = ValueOf(&p).Method(1) @@ -1759,6 +1784,8 @@ if i != 425 { t.Errorf("Pointer Value MethodByName returned %d; want 425", i) } + v = ValueOf(&p).MethodByName("NoArgs") + v.Call(nil) // Curried method of interface value. // Have to wrap interface value in a struct to get at it. @@ -1808,6 +1835,9 @@ if i != 275 { t.Errorf("Value MethodByName returned %d; want 275", i) } + v = ValueOf(p).MethodByName("NoArgs") + ValueOf(v.Interface()).Call(nil) + v.Interface().(func())() // Curried method of pointer. v = ValueOf(&p).Method(1) @@ -1826,6 +1856,9 @@ if i != 325 { t.Errorf("Pointer Value MethodByName returned %d; want 325", i) } + v = ValueOf(&p).MethodByName("NoArgs") + ValueOf(v.Interface()).Call(nil) + v.Interface().(func())() // Curried method of pointer to pointer. pp := &p @@ -1881,7 +1914,7 @@ // Curried method of value. tfunc := TypeOf((func(...Point) int)(nil)) - v := ValueOf(p).Method(3) + v := ValueOf(p).Method(4) if tt := v.Type(); tt != tfunc { t.Errorf("Variadic Method Type is %s; want %s", tt, tfunc) } Index: libgo/go/runtime/crash_unix_test.go =================================================================== --- libgo/go/runtime/crash_unix_test.go (revision 246951) +++ libgo/go/runtime/crash_unix_test.go (working copy) @@ -9,6 +9,7 @@ import ( "bytes" "internal/testenv" + "io" "io/ioutil" "os" "os/exec" @@ -153,6 +154,78 @@ } ` +func TestPanicSystemstack(t *testing.T) { + // Test that GOTRACEBACK=crash prints both the system and user + // stack of other threads. + + // The GOTRACEBACK=crash handler takes 0.1 seconds even if + // it's not writing a core file and potentially much longer if + // it is. Skip in short mode. + if testing.Short() { + t.Skip("Skipping in short mode (GOTRACEBACK=crash is slow)") + } + + t.Parallel() + cmd := exec.Command(os.Args[0], "testPanicSystemstackInternal") + cmd = testEnv(cmd) + cmd.Env = append(cmd.Env, "GOTRACEBACK=crash") + pr, pw, err := os.Pipe() + if err != nil { + t.Fatal("creating pipe: ", err) + } + cmd.Stderr = pw + if err := cmd.Start(); err != nil { + t.Fatal("starting command: ", err) + } + defer cmd.Process.Wait() + defer cmd.Process.Kill() + if err := pw.Close(); err != nil { + t.Log("closing write pipe: ", err) + } + defer pr.Close() + + // Wait for "x\nx\n" to indicate readiness. + buf := make([]byte, 4) + _, err = io.ReadFull(pr, buf) + if err != nil || string(buf) != "x\nx\n" { + t.Fatal("subprocess failed; output:\n", string(buf)) + } + + // Send SIGQUIT. + if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil { + t.Fatal("signaling subprocess: ", err) + } + + // Get traceback. + tb, err := ioutil.ReadAll(pr) + if err != nil { + t.Fatal("reading traceback from pipe: ", err) + } + + // Traceback should have two testPanicSystemstackInternal's + // and two blockOnSystemStackInternal's. + if bytes.Count(tb, []byte("testPanicSystemstackInternal")) != 2 { + t.Fatal("traceback missing user stack:\n", string(tb)) + } else if bytes.Count(tb, []byte("blockOnSystemStackInternal")) != 2 { + t.Fatal("traceback missing system stack:\n", string(tb)) + } +} + +func init() { + if len(os.Args) >= 2 && os.Args[1] == "testPanicSystemstackInternal" { + // Get two threads running on the system stack with + // something recognizable in the stack trace. + runtime.GOMAXPROCS(2) + go testPanicSystemstackInternal() + testPanicSystemstackInternal() + } +} + +func testPanicSystemstackInternal() { + runtime.BlockOnSystemStack() + os.Exit(1) // Should be unreachable. +} + func TestSignalExitStatus(t *testing.T) { testenv.MustHaveGoBuild(t) exe, err := buildTestProg(t, "testprog") Index: libgo/go/runtime/export_test.go =================================================================== --- libgo/go/runtime/export_test.go (revision 246951) +++ libgo/go/runtime/export_test.go (working copy) @@ -243,3 +243,16 @@ return } */ + +// BlockOnSystemStack switches to the system stack, prints "x\n" to +// stderr, and blocks in a stack containing +// "runtime.blockOnSystemStackInternal". +func BlockOnSystemStack() { + systemstack(blockOnSystemStackInternal) +} + +func blockOnSystemStackInternal() { + print("x\n") + lock(&deadlock) + lock(&deadlock) +} Index: libgo/go/runtime/runtime1.go =================================================================== --- libgo/go/runtime/runtime1.go (revision 246951) +++ libgo/go/runtime/runtime1.go (working copy) @@ -280,6 +280,12 @@ throw("atomicor8") } + m = [4]byte{0xff, 0xff, 0xff, 0xff} + atomic.And8(&m[1], 0x1) + if m[0] != 0xff || m[1] != 0x1 || m[2] != 0xff || m[3] != 0xff { + throw("atomicand8") + } + *(*uint64)(unsafe.Pointer(&j)) = ^uint64(0) if j == j { throw("float64nan") Index: libgo/go/runtime/sema.go =================================================================== --- libgo/go/runtime/sema.go (revision 246951) +++ libgo/go/runtime/sema.go (working copy) @@ -171,6 +171,7 @@ for x := root.head; x != nil; x = x.next { if x.elem == unsafe.Pointer(addr) { x.acquiretime = t0 + break } } mutexevent(t0-s.acquiretime, 3) Index: libgo/go/text/template/multi_test.go =================================================================== --- libgo/go/text/template/multi_test.go (revision 246951) +++ libgo/go/text/template/multi_test.go (working copy) @@ -363,7 +363,7 @@ {[]string{"{{.}}", ""}, "twice", ""}, } - for _, c := range cases { + for i, c := range cases { root := New("root") var ( @@ -378,7 +378,8 @@ } buf := &bytes.Buffer{} if err := m.Execute(buf, c.in); err != nil { - t.Fatal(err) + t.Error(i, err) + continue } if buf.String() != c.want { t.Errorf("expected string %q: got %q", c.want, buf.String()) @@ -385,3 +386,35 @@ } } } + +// Issue 19249 was a regression in 1.8 caused by the handling of empty +// templates added in that release, which got different answers depending +// on the order templates appeared in the internal map. +func TestIssue19294(t *testing.T) { + // The empty block in "xhtml" should be replaced during execution + // by the contents of "stylesheet", but if the internal map associating + // names with templates is built in the wrong order, the empty block + // looks non-empty and this doesn't happen. + var inlined = map[string]string{ + "stylesheet": `{{define "stylesheet"}}stylesheet{{end}}`, + "xhtml": `{{block "stylesheet" .}}{{end}}`, + } + all := []string{"stylesheet", "xhtml"} + for i := 0; i < 100; i++ { + res, err := New("title.xhtml").Parse(`{{template "xhtml" .}}`) + if err != nil { + t.Fatal(err) + } + for _, name := range all { + _, err := res.New(name).Parse(inlined[name]) + if err != nil { + t.Fatal(err) + } + } + var buf bytes.Buffer + res.Execute(&buf, 0) + if buf.String() != "stylesheet" { + t.Fatalf("iteration %d: got %q; expected %q", i, buf.String(), "stylesheet") + } + } +} Index: libgo/go/text/template/template.go =================================================================== --- libgo/go/text/template/template.go (revision 246951) +++ libgo/go/text/template/template.go (working copy) @@ -127,7 +127,7 @@ // Even if nt == t, we need to install it in the common.tmpl map. if replace, err := t.associate(nt, tree); err != nil { return nil, err - } else if replace { + } else if replace || nt.Tree == nil { nt.Tree = tree } return nt, nil @@ -215,7 +215,7 @@ if new.common != t.common { panic("internal error: associate not common") } - if t.tmpl[new.name] != nil && parse.IsEmptyTree(tree.Root) && t.Tree != nil { + if old := t.tmpl[new.name]; old != nil && parse.IsEmptyTree(tree.Root) && old.Tree != nil { // If a template by that name exists, // don't replace it with an empty template. return false, nil