From: Ian Lance Taylor Date: Wed, 30 Mar 2011 15:33:16 +0000 (+0000) Subject: Update to current Go library. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f72f4169133572cf62f1e872c5657cdbc4d5de2c;p=gcc.git Update to current Go library. From-SVN: r171732 --- diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug243.go b/gcc/testsuite/go.test/test/fixedbugs/bug243.go index 236c14402f7..0c531968e66 100644 --- a/gcc/testsuite/go.test/test/fixedbugs/bug243.go +++ b/gcc/testsuite/go.test/test/fixedbugs/bug243.go @@ -6,12 +6,14 @@ package main -import ( - "net" -) +import "os" + +// Issue 481: closures and var declarations +// with multiple variables assigned from one +// function call. func main() { - var listen, _ = net.Listen("tcp", "127.0.0.1:0") + var listen, _ = Listen("tcp", "127.0.0.1:0") go func() { for { @@ -20,6 +22,31 @@ func main() { } }() - var conn, _ = net.Dial("tcp", "", listen.Addr().String()) + var conn, _ = Dial("tcp", "", listen.Addr().String()) _ = conn } + +// Simulated net interface to exercise bug +// without involving a real network. +type T chan int + +var global T + +func Listen(x, y string) (T, string) { + global = make(chan int) + return global, y +} + +func (t T) Addr() os.Error { + return os.ErrorString("stringer") +} + +func (t T) Accept() (int, string) { + return <-t, "" +} + +func Dial(x, y, z string) (int, string) { + global <- 1 + return 0, "" +} + diff --git a/libgo/MERGE b/libgo/MERGE index 729be060290..b78ba690a54 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -31d7feb9281b +342e3b11f21a The first line of this file holds the Mercurial revision number of the last merge done from the master library sources. diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 6eb752c7e04..0545d7d8396 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -657,6 +657,7 @@ endif # !LIBGO_IS_LINUX endif # !LIBGO_IS_RTEMS go_net_files = \ + go/net/cgo_stub.go \ go/net/dial.go \ go/net/dnsclient.go \ go/net/dnsconfig.go \ @@ -664,10 +665,12 @@ go_net_files = \ $(go_net_newpollserver_file) \ go/net/fd.go \ $(go_net_fd_os_file) \ + go/net/file.go \ go/net/hosts.go \ go/net/ip.go \ go/net/iprawsock.go \ go/net/ipsock.go \ + go/net/lookup.go \ go/net/net.go \ go/net/parse.go \ go/net/pipe.go \ @@ -1095,6 +1098,7 @@ go_go_ast_files = \ go/go/ast/ast.go \ go/go/ast/filter.go \ go/go/ast/print.go \ + go/go/ast/resolve.go \ go/go/ast/scope.go \ go/go/ast/walk.go go_go_doc_files = \ @@ -2327,8 +2331,8 @@ exp/eval/check: $(CHECK_DEPS) $(CHECK) .PHONY: exp/eval/check -go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/token.gox io.gox os.gox \ - reflect.gox unicode.gox utf8.gox +go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/scanner.gox go/token.gox \ + io.gox os.gox reflect.gox unicode.gox utf8.gox $(BUILDPACKAGE) go/ast/check: $(CHECK_DEPS) @$(MKDIR_P) go/ast diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 3af5ffcde16..b7500666197 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -1039,6 +1039,7 @@ go_mime_files = \ @LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go @LIBGO_IS_RTEMS_TRUE@go_net_newpollserver_file = go/net/newpollserver_rtems.go go_net_files = \ + go/net/cgo_stub.go \ go/net/dial.go \ go/net/dnsclient.go \ go/net/dnsconfig.go \ @@ -1046,10 +1047,12 @@ go_net_files = \ $(go_net_newpollserver_file) \ go/net/fd.go \ $(go_net_fd_os_file) \ + go/net/file.go \ go/net/hosts.go \ go/net/ip.go \ go/net/iprawsock.go \ go/net/ipsock.go \ + go/net/lookup.go \ go/net/net.go \ go/net/parse.go \ go/net/pipe.go \ @@ -1483,6 +1486,7 @@ go_go_ast_files = \ go/go/ast/ast.go \ go/go/ast/filter.go \ go/go/ast/print.go \ + go/go/ast/resolve.go \ go/go/ast/scope.go \ go/go/ast/walk.go @@ -4747,8 +4751,8 @@ exp/eval/check: $(CHECK_DEPS) $(CHECK) .PHONY: exp/eval/check -go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/token.gox io.gox os.gox \ - reflect.gox unicode.gox utf8.gox +go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/scanner.gox go/token.gox \ + io.gox os.gox reflect.gox unicode.gox utf8.gox $(BUILDPACKAGE) go/ast/check: $(CHECK_DEPS) @$(MKDIR_P) go/ast diff --git a/libgo/go/archive/tar/writer_test.go b/libgo/go/archive/tar/writer_test.go index 48b89114005..838cb7e1fef 100644 --- a/libgo/go/archive/tar/writer_test.go +++ b/libgo/go/archive/tar/writer_test.go @@ -150,5 +150,8 @@ testLoop: t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v", i, bytediff(expected, actual)) } + if testing.Short() { // The second test is expensive. + break + } } } diff --git a/libgo/go/asn1/asn1.go b/libgo/go/asn1/asn1.go index d06b1d4d776..c5314517b34 100644 --- a/libgo/go/asn1/asn1.go +++ b/libgo/go/asn1/asn1.go @@ -389,6 +389,11 @@ func parseSequenceOf(bytes []byte, sliceType *reflect.SliceType, elemType reflec if err != nil { return } + // We pretend that GENERAL STRINGs are PRINTABLE STRINGs so + // that a sequence of them can be parsed into a []string. + if t.tag == tagGeneralString { + t.tag = tagPrintableString + } if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag { err = StructuralError{"sequence tag mismatch"} return @@ -516,7 +521,11 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam return } if params.explicit { - if t.class == classContextSpecific && t.tag == *params.tag && (t.length == 0 || t.isCompound) { + expectedClass := classContextSpecific + if params.application { + expectedClass = classApplication + } + if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) { if t.length > 0 { t, offset, err = parseTagAndLength(bytes, offset) if err != nil { @@ -551,6 +560,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam if universalTag == tagPrintableString && t.tag == tagIA5String { universalTag = tagIA5String } + // Likewise for GeneralString + if universalTag == tagPrintableString && t.tag == tagGeneralString { + universalTag = tagGeneralString + } // Special case for time: UTCTime and GeneralizedTime both map to the // Go type time.Time. @@ -566,6 +579,11 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam expectedTag = *params.tag } + if !params.explicit && params.application && params.tag != nil { + expectedClass = classApplication + expectedTag = *params.tag + } + // We have unwrapped any explicit tagging at this point. if t.class != expectedClass || t.tag != expectedTag || t.isCompound != compoundType { // Tags don't match. Again, it could be an optional element. @@ -701,6 +719,12 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam v, err = parseIA5String(innerBytes) case tagT61String: v, err = parseT61String(innerBytes) + case tagGeneralString: + // GeneralString is specified in ISO-2022/ECMA-35, + // A brief review suggests that it includes structures + // that allow the encoding to change midstring and + // such. We give up and pass it as an 8-bit string. + v, err = parseT61String(innerBytes) default: err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)} } @@ -776,8 +800,14 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { // Other ASN.1 types are not supported; if it encounters them, // Unmarshal returns a parse error. func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) { + return UnmarshalWithParams(b, val, "") +} + +// UnmarshalWithParams allows field parameters to be specified for the +// top-level element. The form of the params is the same as the field tags. +func UnmarshalWithParams(b []byte, val interface{}, params string) (rest []byte, err os.Error) { v := reflect.NewValue(val).(*reflect.PtrValue).Elem() - offset, err := parseField(v, b, 0, fieldParameters{}) + offset, err := parseField(v, b, 0, parseFieldParameters(params)) if err != nil { return nil, err } diff --git a/libgo/go/asn1/asn1_test.go b/libgo/go/asn1/asn1_test.go index 34b5f1ecda6..b7767656a42 100644 --- a/libgo/go/asn1/asn1_test.go +++ b/libgo/go/asn1/asn1_test.go @@ -249,11 +249,12 @@ var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParame {"printable", fieldParameters{stringType: tagPrintableString}}, {"optional", fieldParameters{optional: true}}, {"explicit", fieldParameters{explicit: true, tag: new(int)}}, + {"application", fieldParameters{application: true, tag: new(int)}}, {"optional,explicit", fieldParameters{optional: true, explicit: true, tag: new(int)}}, {"default:42", fieldParameters{defaultValue: newInt64(42)}}, {"tag:17", fieldParameters{tag: newInt(17)}}, {"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}}, - {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, newInt64(42), newInt(17), 0, false}}, + {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, false}}, {"set", fieldParameters{set: true}}, } diff --git a/libgo/go/asn1/common.go b/libgo/go/asn1/common.go index 4a5eca1450f..f2254a41bba 100644 --- a/libgo/go/asn1/common.go +++ b/libgo/go/asn1/common.go @@ -32,6 +32,7 @@ const ( tagIA5String = 22 tagUTCTime = 23 tagGeneralizedTime = 24 + tagGeneralString = 27 ) const ( @@ -67,7 +68,8 @@ type tagAndLength struct { // fieldParameters is the parsed representation of tag string from a structure field. type fieldParameters struct { optional bool // true iff the field is OPTIONAL - explicit bool // true iff and EXPLICIT tag is in use. + explicit bool // true iff an EXPLICIT tag is in use. + application bool // true iff an APPLICATION tag is in use. defaultValue *int64 // a default value for INTEGER typed fields (maybe nil). tag *int // the EXPLICIT or IMPLICIT tag (maybe nil). stringType int // the string tag to use when marshaling. @@ -89,7 +91,6 @@ func parseFieldParameters(str string) (ret fieldParameters) { ret.explicit = true if ret.tag == nil { ret.tag = new(int) - *ret.tag = 0 } case part == "ia5": ret.stringType = tagIA5String @@ -109,6 +110,11 @@ func parseFieldParameters(str string) (ret fieldParameters) { } case part == "set": ret.set = true + case part == "application": + ret.application = true + if ret.tag == nil { + ret.tag = new(int) + } } } return diff --git a/libgo/go/big/int_test.go b/libgo/go/big/int_test.go index c0cc9accf1a..9c19dd5da6d 100644 --- a/libgo/go/big/int_test.go +++ b/libgo/go/big/int_test.go @@ -716,18 +716,25 @@ var composites = []string{ func TestProbablyPrime(t *testing.T) { + nreps := 20 + if testing.Short() { + nreps = 1 + } for i, s := range primes { p, _ := new(Int).SetString(s, 10) - if !ProbablyPrime(p, 20) { + if !ProbablyPrime(p, nreps) { t.Errorf("#%d prime found to be non-prime (%s)", i, s) } } for i, s := range composites { c, _ := new(Int).SetString(s, 10) - if ProbablyPrime(c, 20) { + if ProbablyPrime(c, nreps) { t.Errorf("#%d composite found to be prime (%s)", i, s) } + if testing.Short() { + break + } } } diff --git a/libgo/go/bytes/buffer_test.go b/libgo/go/bytes/buffer_test.go index 56a2d927539..14f9501416e 100644 --- a/libgo/go/bytes/buffer_test.go +++ b/libgo/go/bytes/buffer_test.go @@ -178,7 +178,11 @@ func TestBasicOperations(t *testing.T) { func TestLargeStringWrites(t *testing.T) { var buf Buffer - for i := 3; i < 30; i += 3 { + limit := 30 + if testing.Short() { + limit = 9 + } + for i := 3; i < limit; i += 3 { s := fillString(t, "TestLargeWrites (1)", &buf, "", 5, data) empty(t, "TestLargeStringWrites (2)", &buf, s, make([]byte, len(data)/i)) } @@ -188,7 +192,11 @@ func TestLargeStringWrites(t *testing.T) { func TestLargeByteWrites(t *testing.T) { var buf Buffer - for i := 3; i < 30; i += 3 { + limit := 30 + if testing.Short() { + limit = 9 + } + for i := 3; i < limit; i += 3 { s := fillBytes(t, "TestLargeWrites (1)", &buf, "", 5, bytes) empty(t, "TestLargeByteWrites (2)", &buf, s, make([]byte, len(data)/i)) } diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go index bfe2ef39db5..c12a1357383 100644 --- a/libgo/go/bytes/bytes.go +++ b/libgo/go/bytes/bytes.go @@ -293,20 +293,10 @@ func Join(a [][]byte, sep []byte) []byte { } b := make([]byte, n) - bp := 0 - for i := 0; i < len(a); i++ { - s := a[i] - for j := 0; j < len(s); j++ { - b[bp] = s[j] - bp++ - } - if i+1 < len(a) { - s = sep - for j := 0; j < len(s); j++ { - b[bp] = s[j] - bp++ - } - } + bp := copy(b, a[0]) + for _, s := range a[1:] { + bp += copy(b[bp:], sep) + bp += copy(b[bp:], s) } return b } diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go index 063686ec5d6..4ce291a4f67 100644 --- a/libgo/go/bytes/bytes_test.go +++ b/libgo/go/bytes/bytes_test.go @@ -201,7 +201,10 @@ func TestIndexByte(t *testing.T) { // test a larger buffer with different sizes and alignments func TestIndexByteBig(t *testing.T) { - const n = 1024 + var n = 1024 + if testing.Short() { + n = 128 + } b := make([]byte, n) for i := 0; i < n; i++ { // different start alignments diff --git a/libgo/go/container/vector/numbers_test.go b/libgo/go/container/vector/numbers_test.go index d540ace0502..b83b0bfeeff 100644 --- a/libgo/go/container/vector/numbers_test.go +++ b/libgo/go/container/vector/numbers_test.go @@ -33,6 +33,9 @@ func s(n uint64) string { func TestVectorNums(t *testing.T) { + if testing.Short() { + return + } var v Vector c := int(0) runtime.GC() @@ -51,6 +54,9 @@ func TestVectorNums(t *testing.T) { func TestIntVectorNums(t *testing.T) { + if testing.Short() { + return + } var v IntVector c := int(0) runtime.GC() @@ -69,6 +75,9 @@ func TestIntVectorNums(t *testing.T) { func TestStringVectorNums(t *testing.T) { + if testing.Short() { + return + } var v StringVector c := "" runtime.GC() diff --git a/libgo/go/crypto/cipher/ctr.go b/libgo/go/crypto/cipher/ctr.go index 04436ec23b0..147b74fc2fd 100644 --- a/libgo/go/crypto/cipher/ctr.go +++ b/libgo/go/crypto/cipher/ctr.go @@ -22,6 +22,10 @@ type ctr struct { // NewCTR returns a Stream which encrypts/decrypts using the given Block in // counter mode. The length of iv must be the same as the Block's block size. func NewCTR(block Block, iv []byte) Stream { + if len(iv) != block.BlockSize() { + panic("cipher.NewCTR: iv length must equal block size") + } + return &ctr{ b: block, ctr: dup(iv), diff --git a/libgo/go/crypto/ecdsa/ecdsa_test.go b/libgo/go/crypto/ecdsa/ecdsa_test.go index cc22b7a52f1..d6b40391421 100644 --- a/libgo/go/crypto/ecdsa/ecdsa_test.go +++ b/libgo/go/crypto/ecdsa/ecdsa_test.go @@ -20,12 +20,15 @@ func testKeyGeneration(t *testing.T, c *elliptic.Curve, tag string) { return } if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) { - t.Errorf("%s: public key invalid", tag, err) + t.Errorf("%s: public key invalid: %s", tag, err) } } func TestKeyGeneration(t *testing.T) { testKeyGeneration(t, elliptic.P224(), "p224") + if testing.Short() { + return + } testKeyGeneration(t, elliptic.P256(), "p256") testKeyGeneration(t, elliptic.P384(), "p384") testKeyGeneration(t, elliptic.P521(), "p521") @@ -53,6 +56,9 @@ func testSignAndVerify(t *testing.T, c *elliptic.Curve, tag string) { func TestSignAndVerify(t *testing.T) { testSignAndVerify(t, elliptic.P224(), "p224") + if testing.Short() { + return + } testSignAndVerify(t, elliptic.P256(), "p256") testSignAndVerify(t, elliptic.P384(), "p384") testSignAndVerify(t, elliptic.P521(), "p521") @@ -214,5 +220,8 @@ func TestVectors(t *testing.T) { if Verify(&pub, hashed, r, s) != test.ok { t.Errorf("%d: bad result", i) } + if testing.Short() { + break + } } } diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go index 6ae6fb96d3b..02083a98666 100644 --- a/libgo/go/crypto/elliptic/elliptic_test.go +++ b/libgo/go/crypto/elliptic/elliptic_test.go @@ -297,6 +297,9 @@ func TestBaseMult(t *testing.T) { if fmt.Sprintf("%x", x) != e.x || fmt.Sprintf("%x", y) != e.y { t.Errorf("%d: bad output for k=%s: got (%x, %s), want (%s, %s)", i, e.k, x, y, e.x, e.y) } + if testing.Short() && i > 5 { + break + } } } diff --git a/libgo/go/crypto/openpgp/s2k/s2k_test.go b/libgo/go/crypto/openpgp/s2k/s2k_test.go index 814b78627f4..75bc47ec10b 100644 --- a/libgo/go/crypto/openpgp/s2k/s2k_test.go +++ b/libgo/go/crypto/openpgp/s2k/s2k_test.go @@ -90,5 +90,8 @@ func TestParse(t *testing.T) { if !bytes.Equal(out, expected) { t.Errorf("%d: output got: %x want: %x", i, out, expected) } + if testing.Short() { + break + } } } diff --git a/libgo/go/crypto/rand/rand_test.go b/libgo/go/crypto/rand/rand_test.go index f64ead4cab4..bfae7ce4f9b 100644 --- a/libgo/go/crypto/rand/rand_test.go +++ b/libgo/go/crypto/rand/rand_test.go @@ -11,7 +11,11 @@ import ( ) func TestRead(t *testing.T) { - b := make([]byte, 4e6) + var n int = 4e6 + if testing.Short() { + n = 1e5 + } + b := make([]byte, n) n, err := Read(b) if n != len(b) || err != nil { t.Fatalf("Read(buf) = %d, %s", n, err) diff --git a/libgo/go/crypto/rsa/pkcs1v15_test.go b/libgo/go/crypto/rsa/pkcs1v15_test.go index 7b2ce08cb0b..30a4824a6b0 100644 --- a/libgo/go/crypto/rsa/pkcs1v15_test.go +++ b/libgo/go/crypto/rsa/pkcs1v15_test.go @@ -97,7 +97,11 @@ func TestEncryptPKCS1v15(t *testing.T) { return true } - quick.Check(tryEncryptDecrypt, nil) + config := new(quick.Config) + if testing.Short() { + config.MaxCount = 10 + } + quick.Check(tryEncryptDecrypt, config) } // These test vectors were generated with `openssl rsautl -pkcs -encrypt` diff --git a/libgo/go/crypto/rsa/rsa_test.go b/libgo/go/crypto/rsa/rsa_test.go index 22d4576e8dd..bf7c05137a3 100644 --- a/libgo/go/crypto/rsa/rsa_test.go +++ b/libgo/go/crypto/rsa/rsa_test.go @@ -15,7 +15,11 @@ import ( func TestKeyGeneration(t *testing.T) { random := rand.Reader - priv, err := GenerateKey(random, 1024) + size := 1024 + if testing.Short() { + size = 128 + } + priv, err := GenerateKey(random, size) if err != nil { t.Errorf("failed to generate key") } @@ -99,6 +103,9 @@ func TestDecryptOAEP(t *testing.T) { t.Errorf("#%d,%d (blind) bad result: %#v (want %#v)", i, j, out, message.in) } } + if testing.Short() { + break + } } } diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go index 81b5a07446e..c7792343942 100644 --- a/libgo/go/crypto/tls/common.go +++ b/libgo/go/crypto/tls/common.go @@ -93,9 +93,10 @@ const ( // ConnectionState records basic TLS details about the connection. type ConnectionState struct { - HandshakeComplete bool - CipherSuite uint16 - NegotiatedProtocol string + HandshakeComplete bool + CipherSuite uint16 + NegotiatedProtocol string + NegotiatedProtocolIsMutual bool // the certificate chain that was presented by the other side PeerCertificates []*x509.Certificate @@ -124,7 +125,6 @@ type Config struct { RootCAs *CASet // NextProtos is a list of supported, application level protocols. - // Currently only server-side handling is supported. NextProtos []string // ServerName is included in the client's handshake to support virtual diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go index 1e6fe60aec2..b94e235c814 100644 --- a/libgo/go/crypto/tls/conn.go +++ b/libgo/go/crypto/tls/conn.go @@ -35,7 +35,8 @@ type Conn struct { ocspResponse []byte // stapled OCSP response peerCertificates []*x509.Certificate - clientProtocol string + clientProtocol string + clientProtocolFallback bool // first permanent error errMutex sync.Mutex @@ -761,6 +762,7 @@ func (c *Conn) ConnectionState() ConnectionState { state.HandshakeComplete = c.handshakeComplete if c.handshakeComplete { state.NegotiatedProtocol = c.clientProtocol + state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback state.CipherSuite = c.cipherSuite state.PeerCertificates = c.peerCertificates } diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go index a325a9b953c..540b25c8753 100644 --- a/libgo/go/crypto/tls/handshake_client.go +++ b/libgo/go/crypto/tls/handshake_client.go @@ -29,6 +29,7 @@ func (c *Conn) clientHandshake() os.Error { serverName: c.config.ServerName, supportedCurves: []uint16{curveP256, curveP384, curveP521}, supportedPoints: []uint8{pointFormatUncompressed}, + nextProtoNeg: len(c.config.NextProtos) > 0, } t := uint32(c.config.time()) @@ -66,6 +67,11 @@ func (c *Conn) clientHandshake() os.Error { return c.sendAlert(alertUnexpectedMessage) } + if !hello.nextProtoNeg && serverHello.nextProtoNeg { + c.sendAlert(alertHandshakeFailure) + return os.ErrorString("server advertised unrequested NPN") + } + suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite) if suite == nil { return c.sendAlert(alertHandshakeFailure) @@ -267,6 +273,17 @@ func (c *Conn) clientHandshake() os.Error { c.out.prepareCipherSpec(clientCipher, clientHash) c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) + if serverHello.nextProtoNeg { + nextProto := new(nextProtoMsg) + proto, fallback := mutualProtocol(c.config.NextProtos, serverHello.nextProtos) + nextProto.proto = proto + c.clientProtocol = proto + c.clientProtocolFallback = fallback + + finishedHash.Write(nextProto.marshal()) + c.writeRecord(recordTypeHandshake, nextProto.marshal()) + } + finished := new(finishedMsg) finished.verifyData = finishedHash.clientSum(masterSecret) finishedHash.Write(finished.marshal()) @@ -299,3 +316,19 @@ func (c *Conn) clientHandshake() os.Error { c.cipherSuite = suiteId return nil } + +// mutualProtocol finds the mutual Next Protocol Negotiation protocol given the +// set of client and server supported protocols. The set of client supported +// protocols must not be empty. It returns the resulting protocol and flag +// indicating if the fallback case was reached. +func mutualProtocol(clientProtos, serverProtos []string) (string, bool) { + for _, s := range serverProtos { + for _, c := range clientProtos { + if s == c { + return s, false + } + } + } + + return clientProtos[0], true +} diff --git a/libgo/go/crypto/tls/handshake_client_test.go b/libgo/go/crypto/tls/handshake_client_test.go index fd1f145cfc4..3f91c7acf1f 100644 --- a/libgo/go/crypto/tls/handshake_client_test.go +++ b/libgo/go/crypto/tls/handshake_client_test.go @@ -50,7 +50,7 @@ func TestRunClient(t *testing.T) { testConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA} - conn, err := Dial("tcp", "", "127.0.0.1:10443", testConfig) + conn, err := Dial("tcp", "127.0.0.1:10443", testConfig) if err != nil { t.Fatal(err) } diff --git a/libgo/go/crypto/tls/handshake_messages_test.go b/libgo/go/crypto/tls/handshake_messages_test.go index 21577dd0b01..0b93b89f1ad 100644 --- a/libgo/go/crypto/tls/handshake_messages_test.go +++ b/libgo/go/crypto/tls/handshake_messages_test.go @@ -34,7 +34,11 @@ func TestMarshalUnmarshal(t *testing.T) { for i, iface := range tests { ty := reflect.NewValue(iface).Type() - for j := 0; j < 100; j++ { + n := 100 + if testing.Short() { + n = 5 + } + for j := 0; j < n; j++ { v, ok := quick.Value(ty, rand) if !ok { t.Errorf("#%d: failed to create value", i) diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go index e8290d728dd..f66449c8225 100644 --- a/libgo/go/crypto/tls/tls.go +++ b/libgo/go/crypto/tls/tls.go @@ -87,8 +87,9 @@ func Listen(network, laddr string, config *Config) (*Listener, os.Error) { // Dial interprets a nil configuration as equivalent to // the zero configuration; see the documentation of Config // for the defaults. -func Dial(network, laddr, raddr string, config *Config) (*Conn, os.Error) { - c, err := net.Dial(network, laddr, raddr) +func Dial(network, addr string, config *Config) (*Conn, os.Error) { + raddr := addr + c, err := net.Dial(network, raddr) if err != nil { return nil, err } diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index 3af8ba8ca24..853bcde9ad8 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -304,6 +304,42 @@ const ( KeyUsageDecipherOnly ) +// RFC 5280, 4.2.1.12 Extended Key Usage +// +// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } +// +// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } +// +// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } +// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } +// id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } +// id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } +// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } +// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } +var ( + oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} + oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} + oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} + oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} + oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} + oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} + oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} +) + +// ExtKeyUsage represents an extended set of actions that are valid for a given key. +// Each of the ExtKeyUsage* constants define a unique action. +type ExtKeyUsage int + +const ( + ExtKeyUsageAny ExtKeyUsage = iota + ExtKeyUsageServerAuth + ExtKeyUsageClientAuth + ExtKeyUsageCodeSigning + ExtKeyUsageEmailProtection + ExtKeyUsageTimeStamping + ExtKeyUsageOCSPSigning +) + // A Certificate represents an X.509 certificate. type Certificate struct { Raw []byte // Raw ASN.1 DER contents. @@ -320,6 +356,9 @@ type Certificate struct { NotBefore, NotAfter *time.Time // Validity bounds. KeyUsage KeyUsage + ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages. + UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package. + BasicConstraintsValid bool // if true then the next two fields are valid. IsCA bool MaxPathLen int @@ -666,6 +705,44 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { out.AuthorityKeyId = a.Id continue + case 37: + // RFC 5280, 4.2.1.12. Extended Key Usage + + // id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } + // + // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + // + // KeyPurposeId ::= OBJECT IDENTIFIER + + var keyUsage []asn1.ObjectIdentifier + _, err = asn1.Unmarshal(e.Value, &keyUsage) + if err != nil { + return nil, err + } + + for _, u := range keyUsage { + switch { + case u.Equal(oidExtKeyUsageAny): + out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageAny) + case u.Equal(oidExtKeyUsageServerAuth): + out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageServerAuth) + case u.Equal(oidExtKeyUsageClientAuth): + out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageClientAuth) + case u.Equal(oidExtKeyUsageCodeSigning): + out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageCodeSigning) + case u.Equal(oidExtKeyUsageEmailProtection): + out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageEmailProtection) + case u.Equal(oidExtKeyUsageTimeStamping): + out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageTimeStamping) + case u.Equal(oidExtKeyUsageOCSPSigning): + out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageOCSPSigning) + default: + out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u) + } + } + + continue + case 14: // RFC 5280, 4.2.1.2 var keyid []byte diff --git a/libgo/go/debug/gosym/pclntab_test.go b/libgo/go/debug/gosym/pclntab_test.go index 90870217348..c83e64eabd7 100644 --- a/libgo/go/debug/gosym/pclntab_test.go +++ b/libgo/go/debug/gosym/pclntab_test.go @@ -143,9 +143,6 @@ func TestLineAline(t *testing.T) { } } -// gotest: if [ "$(uname)-$(uname -m)" = Linux-x86_64 -a "$GOARCH" = amd64 ]; then -// gotest: mkdir -p _test && $AS pclinetest.s && $LD -E main -o _test/pclinetest pclinetest.$O -// gotest: fi func TestPCLine(t *testing.T) { if !dotest() { return diff --git a/libgo/go/ebnf/ebnf_test.go b/libgo/go/ebnf/ebnf_test.go index 69ad5fed1cf..e77cf64adfa 100644 --- a/libgo/go/ebnf/ebnf_test.go +++ b/libgo/go/ebnf/ebnf_test.go @@ -15,31 +15,26 @@ var fset = token.NewFileSet() var grammars = []string{ -`Program = . -`, - -`Program = foo . -foo = "foo" . -`, - -`Program = "a" | "b" "c" . -`, - -`Program = "a" ... "z" . -`, - -`Program = Song . - Song = { Note } . - Note = Do | (Re | Mi | Fa | So | La) | Ti . - Do = "c" . - Re = "d" . - Mi = "e" . - Fa = "f" . - So = "g" . - La = "a" . - Ti = ti . - ti = "b" . -`, + `Program = .`, + + `Program = foo . + foo = "foo" .`, + + `Program = "a" | "b" "c" .`, + + `Program = "a" ... "z" .`, + + `Program = Song . + Song = { Note } . + Note = Do | (Re | Mi | Fa | So | La) | Ti . + Do = "c" . + Re = "d" . + Mi = "e" . + Fa = "f" . + So = "g" . + La = "a" . + Ti = ti . + ti = "b" .`, } diff --git a/libgo/go/ebnf/parser.go b/libgo/go/ebnf/parser.go index c38530177ac..818168e111d 100644 --- a/libgo/go/ebnf/parser.go +++ b/libgo/go/ebnf/parser.go @@ -18,7 +18,7 @@ type parser struct { scanner scanner.Scanner pos token.Pos // token position tok token.Token // one token look-ahead - lit []byte // token literal + lit string // token literal } @@ -44,7 +44,7 @@ func (p *parser) errorExpected(pos token.Pos, msg string) { // make the error message more specific msg += ", found '" + p.tok.String() + "'" if p.tok.IsLiteral() { - msg += " " + string(p.lit) + msg += " " + p.lit } } p.error(pos, msg) @@ -63,7 +63,7 @@ func (p *parser) expect(tok token.Token) token.Pos { func (p *parser) parseIdentifier() *Name { pos := p.pos - name := string(p.lit) + name := p.lit p.expect(token.IDENT) return &Name{pos, name} } @@ -73,7 +73,7 @@ func (p *parser) parseToken() *Token { pos := p.pos value := "" if p.tok == token.STRING { - value, _ = strconv.Unquote(string(p.lit)) + value, _ = strconv.Unquote(p.lit) // Unquote may fail with an error, but only if the scanner found // an illegal string in the first place. In this case the error // has already been reported. diff --git a/libgo/go/exp/datafmt/parser.go b/libgo/go/exp/datafmt/parser.go index c6d1402644c..7dedb531a51 100644 --- a/libgo/go/exp/datafmt/parser.go +++ b/libgo/go/exp/datafmt/parser.go @@ -22,7 +22,7 @@ type parser struct { file *token.File pos token.Pos // token position tok token.Token // one token look-ahead - lit []byte // token literal + lit string // token literal packs map[string]string // PackageName -> ImportPath rules map[string]expr // RuleName -> Expression @@ -62,7 +62,7 @@ func (p *parser) errorExpected(pos token.Pos, msg string) { // make the error message more specific msg += ", found '" + p.tok.String() + "'" if p.tok.IsLiteral() { - msg += " " + string(p.lit) + msg += " " + p.lit } } p.error(pos, msg) @@ -80,7 +80,7 @@ func (p *parser) expect(tok token.Token) token.Pos { func (p *parser) parseIdentifier() string { - name := string(p.lit) + name := p.lit p.expect(token.IDENT) return name } @@ -130,7 +130,7 @@ func (p *parser) parseRuleName() (string, bool) { func (p *parser) parseString() string { s := "" if p.tok == token.STRING { - s, _ = strconv.Unquote(string(p.lit)) + s, _ = strconv.Unquote(p.lit) // Unquote may fail with an error, but only if the scanner found // an illegal string in the first place. In this case the error // has already been reported. @@ -181,7 +181,7 @@ func (p *parser) parseField() expr { var fname string switch p.tok { case token.ILLEGAL: - if string(p.lit) != "@" { + if p.lit != "@" { return nil } fname = "@" diff --git a/libgo/go/exp/draw/x11/conn.go b/libgo/go/exp/draw/x11/conn.go index e28fb217065..53294af15c0 100644 --- a/libgo/go/exp/draw/x11/conn.go +++ b/libgo/go/exp/draw/x11/conn.go @@ -286,11 +286,11 @@ func connect(display string) (conn net.Conn, displayStr string, err os.Error) { } // Make the connection. if socket != "" { - conn, err = net.Dial("unix", "", socket+":"+displayStr) + conn, err = net.Dial("unix", socket+":"+displayStr) } else if host != "" { - conn, err = net.Dial(protocol, "", host+":"+strconv.Itoa(6000+displayInt)) + conn, err = net.Dial(protocol, host+":"+strconv.Itoa(6000+displayInt)) } else { - conn, err = net.Dial("unix", "", "/tmp/.X11-unix/X"+displayStr) + conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+displayStr) } if err != nil { return nil, "", os.NewError("cannot connect to " + display + ": " + err.String()) diff --git a/libgo/go/exp/eval/eval_test.go b/libgo/go/exp/eval/eval_test.go index ff28cf1a908..541d3feb71d 100644 --- a/libgo/go/exp/eval/eval_test.go +++ b/libgo/go/exp/eval/eval_test.go @@ -39,9 +39,13 @@ type job struct { } func runTests(t *testing.T, baseName string, tests []test) { - for i, test := range tests { + delta := 1 + if testing.Short() { + delta = 16 + } + for i := 0; i < len(tests); i += delta { name := fmt.Sprintf("%s[%d]", baseName, i) - test.run(t, name) + tests[i].run(t, name) } } diff --git a/libgo/go/exp/ogle/cmd.go b/libgo/go/exp/ogle/cmd.go index 9920ff6b883..ba056e88baf 100644 --- a/libgo/go/exp/ogle/cmd.go +++ b/libgo/go/exp/ogle/cmd.go @@ -205,7 +205,7 @@ func parseLoad(args []byte) (ident string, path string, err os.Error) { sc, ev := newScanner(args) var toks [4]token.Token - var lits [4][]byte + var lits [4]string for i := range toks { _, toks[i], lits[i] = sc.Scan() } diff --git a/libgo/go/flag/flag.go b/libgo/go/flag/flag.go index 14f4d522c6a..19a3104553f 100644 --- a/libgo/go/flag/flag.go +++ b/libgo/go/flag/flag.go @@ -56,7 +56,7 @@ flag.Bool(...) // global options flag.Parse() // parse leading command - subcmd := flag.Arg[0] + subcmd := flag.Arg(0) switch subcmd { // add per-subcommand options } diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go index c8aa6090bbf..4d308ac342d 100644 --- a/libgo/go/fmt/fmt_test.go +++ b/libgo/go/fmt/fmt_test.go @@ -442,6 +442,9 @@ func BenchmarkSprintfPrefixedInt(b *testing.B) { } func TestCountMallocs(t *testing.T) { + if testing.Short() { + return + } mallocs := 0 - runtime.MemStats.Mallocs for i := 0; i < 100; i++ { Sprintf("") diff --git a/libgo/go/go/ast/ast.go b/libgo/go/go/ast/ast.go index 4a4c12b7c0a..ed3e2cdd9be 100644 --- a/libgo/go/go/ast/ast.go +++ b/libgo/go/go/ast/ast.go @@ -66,7 +66,7 @@ type Decl interface { // A Comment node represents a single //-style or /*-style comment. type Comment struct { Slash token.Pos // position of "/" starting the comment - Text []byte // comment text (excluding '\n' for //-style comments) + Text string // comment text (excluding '\n' for //-style comments) } @@ -199,7 +199,7 @@ type ( BasicLit struct { ValuePos token.Pos // literal position Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING - Value []byte // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o` + Value string // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o` } // A FuncLit node represents a function literal. @@ -781,7 +781,7 @@ type ( ImportSpec struct { Doc *CommentGroup // associated documentation; or nil Name *Ident // local package name (including "."); or nil - Path *BasicLit // package path + Path *BasicLit // import path Comment *CommentGroup // line comments; or nil } @@ -925,8 +925,9 @@ type File struct { Package token.Pos // position of "package" keyword Name *Ident // package name Decls []Decl // top-level declarations; or nil - Scope *Scope // package scope - Unresolved []*Ident // unresolved global identifiers + Scope *Scope // package scope (this file only) + Imports []*ImportSpec // imports in this file + Unresolved []*Ident // unresolved identifiers in this file Comments []*CommentGroup // list of all comments in the source file } @@ -944,9 +945,10 @@ func (f *File) End() token.Pos { // collectively building a Go package. // type Package struct { - Name string // package name - Scope *Scope // package scope - Files map[string]*File // Go source files by filename + Name string // package name + Scope *Scope // package scope + Imports map[string]*Scope // map of import path -> package scope across all files + Files map[string]*File // Go source files by filename } diff --git a/libgo/go/go/ast/filter.go b/libgo/go/go/ast/filter.go index 4da487ce02a..090d08d34c7 100644 --- a/libgo/go/go/ast/filter.go +++ b/libgo/go/go/ast/filter.go @@ -304,7 +304,7 @@ const ( // separator is an empty //-style comment that is interspersed between // different comment groups when they are concatenated into a single group // -var separator = &Comment{noPos, []byte("//")} +var separator = &Comment{noPos, "//"} // MergePackageFiles creates a file AST by merging the ASTs of the @@ -426,5 +426,6 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File { } // TODO(gri) need to compute pkgScope and unresolved identifiers! - return &File{doc, pos, NewIdent(pkg.Name), decls, nil, nil, comments} + // TODO(gri) need to compute imports! + return &File{doc, pos, NewIdent(pkg.Name), decls, nil, nil, nil, comments} } diff --git a/libgo/go/go/ast/resolve.go b/libgo/go/go/ast/resolve.go new file mode 100644 index 00000000000..fddc3baab86 --- /dev/null +++ b/libgo/go/go/ast/resolve.go @@ -0,0 +1,188 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements NewPackage. + +package ast + +import ( + "fmt" + "go/scanner" + "go/token" + "os" +) + + +type pkgBuilder struct { + scanner.ErrorVector + fset *token.FileSet +} + + +func (p *pkgBuilder) error(pos token.Pos, msg string) { + p.Error(p.fset.Position(pos), msg) +} + + +func (p *pkgBuilder) errorf(pos token.Pos, format string, args ...interface{}) { + p.error(pos, fmt.Sprintf(format, args...)) +} + + +func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) { + alt := scope.Insert(obj) + if alt == nil && altScope != nil { + // see if there is a conflicting declaration in altScope + alt = altScope.Lookup(obj.Name) + } + if alt != nil { + prevDecl := "" + if pos := alt.Pos(); pos.IsValid() { + prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.fset.Position(pos)) + } + p.error(obj.Pos(), fmt.Sprintf("%s redeclared in this block%s", obj.Name, prevDecl)) + } +} + + +func resolve(scope *Scope, ident *Ident) bool { + for ; scope != nil; scope = scope.Outer { + if obj := scope.Lookup(ident.Name); obj != nil { + ident.Obj = obj + return true + } + } + return false +} + + +// NewPackage uses an Importer to resolve imports. Given an importPath, +// an importer returns the imported package's name, its scope of exported +// objects, and an error, if any. +// +type Importer func(path string) (name string, scope *Scope, err os.Error) + + +// NewPackage creates a new Package node from a set of File nodes. It resolves +// unresolved identifiers across files and updates each file's Unresolved list +// accordingly. If a non-nil importer and universe scope are provided, they are +// used to resolve identifiers not declared in any of the package files. Any +// remaining unresolved identifiers are reported as undeclared. If the files +// belong to different packages, one package name is selected and files with +// different package name are reported and then ignored. +// The result is a package node and a scanner.ErrorList if there were errors. +// +func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, os.Error) { + var p pkgBuilder + p.fset = fset + + // complete package scope + pkgName := "" + pkgScope := NewScope(universe) + for _, file := range files { + // package names must match + switch name := file.Name.Name; { + case pkgName == "": + pkgName = name + case name != pkgName: + p.errorf(file.Package, "package %s; expected %s", name, pkgName) + continue // ignore this file + } + + // collect top-level file objects in package scope + for _, obj := range file.Scope.Objects { + p.declare(pkgScope, nil, obj) + } + } + + // imports maps import paths to package names and scopes + // TODO(gri): Eventually we like to get to the import scope from + // a package object. Then we can have a map path -> Obj. + type importedPkg struct { + name string + scope *Scope + } + imports := make(map[string]*importedPkg) + + // complete file scopes with imports and resolve identifiers + for _, file := range files { + // ignore file if it belongs to a different package + // (error has already been reported) + if file.Name.Name != pkgName { + continue + } + + // build file scope by processing all imports + importErrors := false + fileScope := NewScope(pkgScope) + for _, spec := range file.Imports { + // add import to global map of imports + path := string(spec.Path.Value) + path = path[1 : len(path)-1] // strip ""'s + pkg := imports[path] + if pkg == nil { + if importer == nil { + importErrors = true + continue + } + name, scope, err := importer(path) + if err != nil { + p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err) + importErrors = true + continue + } + pkg = &importedPkg{name, scope} + imports[path] = pkg + // TODO(gri) If a local package name != "." is provided, + // global identifier resolution could proceed even if the + // import failed. Consider adjusting the logic here a bit. + } + // local name overrides imported package name + name := pkg.name + if spec.Name != nil { + name = spec.Name.Name + } + // add import to file scope + if name == "." { + // merge imported scope with file scope + for _, obj := range pkg.scope.Objects { + p.declare(fileScope, pkgScope, obj) + } + } else { + // declare imported package object in file scope + obj := NewObj(Pkg, name) + obj.Decl = spec + p.declare(fileScope, pkgScope, obj) + } + } + + // resolve identifiers + if importErrors { + // don't use the universe scope without correct imports + // (objects in the universe may be shadowed by imports; + // with missing imports identifiers might get resolved + // wrongly) + pkgScope.Outer = nil + } + i := 0 + for _, ident := range file.Unresolved { + if !resolve(fileScope, ident) { + p.errorf(ident.Pos(), "undeclared name: %s", ident.Name) + file.Unresolved[i] = ident + i++ + } + + } + file.Unresolved = file.Unresolved[0:i] + pkgScope.Outer = universe // reset universe scope + } + + // collect all import paths and respective package scopes + importedScopes := make(map[string]*Scope) + for path, pkg := range imports { + importedScopes[path] = pkg.scope + } + + return &Package{pkgName, pkgScope, importedScopes, files}, p.GetError(scanner.Sorted) +} diff --git a/libgo/go/go/ast/scope.go b/libgo/go/go/ast/scope.go index 91866dcf57b..830d88aef4a 100644 --- a/libgo/go/go/ast/scope.go +++ b/libgo/go/go/ast/scope.go @@ -39,16 +39,14 @@ func (s *Scope) Lookup(name string) *Object { } -// Insert attempts to insert a named object into the scope s. -// If the scope does not contain an object with that name yet, -// Insert inserts the object and returns it. Otherwise, Insert -// leaves the scope unchanged and returns the object found in -// the scope instead. +// Insert attempts to insert a named object obj into the scope s. +// If the scope already contains an object alt with the same name, +// Insert leaves the scope unchanged and returns alt. Otherwise +// it inserts obj and returns nil." // func (s *Scope) Insert(obj *Object) (alt *Object) { if alt = s.Objects[obj.Name]; alt == nil { s.Objects[obj.Name] = obj - alt = obj } return } @@ -101,6 +99,11 @@ func (obj *Object) Pos() token.Pos { return n.Pos() } } + case *ImportSpec: + if d.Name != nil && d.Name.Name == name { + return d.Name.Pos() + } + return d.Path.Pos() case *ValueSpec: for _, n := range d.Names { if n.Name == name { diff --git a/libgo/go/go/doc/comment.go b/libgo/go/go/doc/comment.go index 9ff0bd536ae..f1ebfa97b9f 100644 --- a/libgo/go/go/doc/comment.go +++ b/libgo/go/go/doc/comment.go @@ -286,7 +286,7 @@ func unindent(block [][]byte) { // nor to have trailing spaces at the end of lines. // The comment markers have already been removed. // -// Turn each run of multiple \n into

+// Turn each run of multiple \n into

. // Turn each run of indented lines into a

 block without indent.
 //
 // URLs in the comment text are converted into links; if the URL also appears
diff --git a/libgo/go/go/doc/doc.go b/libgo/go/go/doc/doc.go
index e46857cb8a1..e7a8d3f63bb 100644
--- a/libgo/go/go/doc/doc.go
+++ b/libgo/go/go/doc/doc.go
@@ -66,7 +66,7 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) {
 	n2 := len(comments.List)
 	list := make([]*ast.Comment, n1+1+n2) // + 1 for separator line
 	copy(list, doc.doc.List)
-	list[n1] = &ast.Comment{token.NoPos, []byte("//")} // separator line
+	list[n1] = &ast.Comment{token.NoPos, "//"} // separator line
 	copy(list[n1+1:], comments.List)
 	doc.doc = &ast.CommentGroup{list}
 }
@@ -105,7 +105,7 @@ func baseTypeName(typ ast.Expr) string {
 		// if the type is not exported, the effect to
 		// a client is as if there were no type name
 		if t.IsExported() {
-			return string(t.Name)
+			return t.Name
 		}
 	case *ast.StarExpr:
 		return baseTypeName(t.X)
@@ -300,9 +300,9 @@ func (doc *docReader) addFile(src *ast.File) {
 	// collect BUG(...) comments
 	for _, c := range src.Comments {
 		text := c.List[0].Text
-		if m := bug_markers.FindIndex(text); m != nil {
+		if m := bug_markers.FindStringIndex(text); m != nil {
 			// found a BUG comment; maybe empty
-			if btxt := text[m[1]:]; bug_content.Match(btxt) {
+			if btxt := text[m[1]:]; bug_content.MatchString(btxt) {
 				// non-empty BUG comment; collect comment without BUG prefix
 				list := copyCommentList(c.List)
 				list[0].Text = text[m[1]:]
diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go
index 6f35b495efa..fc4ae094394 100644
--- a/libgo/go/go/parser/interface.go
+++ b/libgo/go/go/parser/interface.go
@@ -69,7 +69,7 @@ func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr,
 
 	var p parser
 	p.init(fset, filename, data, 0)
-	x := p.parseExpr()
+	x := p.parseRhs()
 	if p.tok == token.SEMICOLON {
 		p.next() // consume automatically inserted semicolon, if any
 	}
@@ -159,7 +159,8 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st
 			name := src.Name.Name
 			pkg, found := pkgs[name]
 			if !found {
-				pkg = &ast.Package{name, nil, make(map[string]*ast.File)}
+				// TODO(gri) Use NewPackage here; reconsider ParseFiles API.
+				pkg = &ast.Package{name, nil, nil, make(map[string]*ast.File)}
 				pkgs[name] = pkg
 			}
 			pkg.Files[filename] = src
diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go
index b0e8c8ad7a8..ad7e4cdcf2e 100644
--- a/libgo/go/go/parser/parser.go
+++ b/libgo/go/go/parser/parser.go
@@ -47,17 +47,18 @@ type parser struct {
 	lineComment *ast.CommentGroup // last line comment
 
 	// Next token
-	pos  token.Pos   // token position
-	tok  token.Token // one token look-ahead
-	lit_ []byte      // token literal (slice into original source, don't hold on to it)
+	pos token.Pos   // token position
+	tok token.Token // one token look-ahead
+	lit string      // token literal
 
 	// Non-syntactic parser control
 	exprLev int // < 0: in control clause, >= 0: in expression
 
 	// Ordinary identifer scopes
-	pkgScope   *ast.Scope   // pkgScope.Outer == nil
-	topScope   *ast.Scope   // top-most scope; may be pkgScope
-	unresolved []*ast.Ident // unresolved global identifiers
+	pkgScope   *ast.Scope        // pkgScope.Outer == nil
+	topScope   *ast.Scope        // top-most scope; may be pkgScope
+	unresolved []*ast.Ident      // unresolved identifiers
+	imports    []*ast.ImportSpec // list of imports
 
 	// Label scope
 	// (maintained by open/close LabelScope)
@@ -95,15 +96,6 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uin
 }
 
 
-func (p *parser) lit() []byte {
-	// make a copy of p.lit_ so that we don't hold on to
-	// a copy of the entire source indirectly in the AST
-	t := make([]byte, len(p.lit_))
-	copy(t, p.lit_)
-	return t
-}
-
-
 // ----------------------------------------------------------------------------
 // Scoping support
 
@@ -141,13 +133,13 @@ func (p *parser) closeLabelScope() {
 
 func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
 	for _, ident := range idents {
+		assert(ident.Obj == nil, "identifier already declared or resolved")
 		if ident.Name != "_" {
 			obj := ast.NewObj(kind, ident.Name)
 			// remember the corresponding declaration for redeclaration
 			// errors and global variable resolution/typechecking phase
 			obj.Decl = decl
-			alt := scope.Insert(obj)
-			if alt != obj && p.mode&DeclarationErrors != 0 {
+			if alt := scope.Insert(obj); alt != nil && p.mode&DeclarationErrors != 0 {
 				prevDecl := ""
 				if pos := alt.Pos(); pos.IsValid() {
 					prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.file.Position(pos))
@@ -166,14 +158,16 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
 	// the same type, and at least one of the non-blank variables is new.
 	n := 0 // number of new variables
 	for _, ident := range idents {
+		assert(ident.Obj == nil, "identifier already declared or resolved")
 		if ident.Name != "_" {
 			obj := ast.NewObj(ast.Var, ident.Name)
 			// short var declarations cannot have redeclaration errors
 			// and are not global => no need to remember the respective
 			// declaration
 			alt := p.topScope.Insert(obj)
-			if alt == obj {
+			if alt == nil {
 				n++ // new declaration
+				alt = obj
 			}
 			ident.Obj = alt
 		}
@@ -184,7 +178,19 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
 }
 
 
-func (p *parser) resolve(ident *ast.Ident) {
+// The unresolved object is a sentinel to mark identifiers that have been added
+// to the list of unresolved identifiers. The sentinel is only used for verifying
+// internal consistency.
+var unresolved = new(ast.Object)
+
+
+func (p *parser) resolve(x ast.Expr) {
+	// nothing to do if x is not an identifier or the blank identifier
+	ident, _ := x.(*ast.Ident)
+	if ident == nil {
+		return
+	}
+	assert(ident.Obj == nil, "identifier already declared or resolved")
 	if ident.Name == "_" {
 		return
 	}
@@ -195,10 +201,12 @@ func (p *parser) resolve(ident *ast.Ident) {
 			return
 		}
 	}
-	// collect unresolved global identifiers; ignore the others
-	if p.topScope == p.pkgScope {
-		p.unresolved = append(p.unresolved, ident)
-	}
+	// all local scopes are known, so any unresolved identifier
+	// must be found either in the file scope, package scope
+	// (perhaps in another file), or universe scope --- collect
+	// them so that they can be resolved later
+	ident.Obj = unresolved
+	p.unresolved = append(p.unresolved, ident)
 }
 
 
@@ -244,7 +252,7 @@ func (p *parser) next0() {
 		s := p.tok.String()
 		switch {
 		case p.tok.IsLiteral():
-			p.printTrace(s, string(p.lit_))
+			p.printTrace(s, p.lit)
 		case p.tok.IsOperator(), p.tok.IsKeyword():
 			p.printTrace("\"" + s + "\"")
 		default:
@@ -252,7 +260,7 @@ func (p *parser) next0() {
 		}
 	}
 
-	p.pos, p.tok, p.lit_ = p.scanner.Scan()
+	p.pos, p.tok, p.lit = p.scanner.Scan()
 }
 
 // Consume a comment and return it and the line on which it ends.
@@ -260,15 +268,16 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
 	// /*-style comments may end on a different line than where they start.
 	// Scan the comment for '\n' chars and adjust endline accordingly.
 	endline = p.file.Line(p.pos)
-	if p.lit_[1] == '*' {
-		for _, b := range p.lit_ {
-			if b == '\n' {
+	if p.lit[1] == '*' {
+		// don't use range here - no need to decode Unicode code points
+		for i := 0; i < len(p.lit); i++ {
+			if p.lit[i] == '\n' {
 				endline++
 			}
 		}
 	}
 
-	comment = &ast.Comment{p.pos, p.lit()}
+	comment = &ast.Comment{p.pos, p.lit}
 	p.next0()
 
 	return
@@ -358,12 +367,12 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
 	if pos == p.pos {
 		// the error happened at the current position;
 		// make the error message more specific
-		if p.tok == token.SEMICOLON && p.lit_[0] == '\n' {
+		if p.tok == token.SEMICOLON && p.lit[0] == '\n' {
 			msg += ", found newline"
 		} else {
 			msg += ", found '" + p.tok.String() + "'"
 			if p.tok.IsLiteral() {
-				msg += " " + string(p.lit_)
+				msg += " " + p.lit
 			}
 		}
 	}
@@ -388,6 +397,13 @@ func (p *parser) expectSemi() {
 }
 
 
+func assert(cond bool, msg string) {
+	if !cond {
+		panic("go/parser internal error: " + msg)
+	}
+}
+
+
 // ----------------------------------------------------------------------------
 // Identifiers
 
@@ -395,7 +411,7 @@ func (p *parser) parseIdent() *ast.Ident {
 	pos := p.pos
 	name := "_"
 	if p.tok == token.IDENT {
-		name = string(p.lit_)
+		name = p.lit
 		p.next()
 	} else {
 		p.expect(token.IDENT) // use expect() error handling
@@ -422,21 +438,51 @@ func (p *parser) parseIdentList() (list []*ast.Ident) {
 // ----------------------------------------------------------------------------
 // Common productions
 
-func (p *parser) parseExprList() (list []ast.Expr) {
+// If lhs is set, result list elements which are identifiers are not resolved.
+func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
 	if p.trace {
 		defer un(trace(p, "ExpressionList"))
 	}
 
-	list = append(list, p.parseExpr())
+	list = append(list, p.parseExpr(lhs))
 	for p.tok == token.COMMA {
 		p.next()
-		list = append(list, p.parseExpr())
+		list = append(list, p.parseExpr(lhs))
 	}
 
 	return
 }
 
 
+func (p *parser) parseLhsList() []ast.Expr {
+	list := p.parseExprList(true)
+	switch p.tok {
+	case token.DEFINE:
+		// lhs of a short variable declaration
+		p.shortVarDecl(p.makeIdentList(list))
+	case token.COLON:
+		// lhs of a label declaration or a communication clause of a select
+		// statement (parseLhsList is not called when parsing the case clause
+		// of a switch statement):
+		// - labels are declared by the caller of parseLhsList
+		// - for communication clauses, if there is a stand-alone identifier
+		//   followed by a colon, we have a syntax error; there is no need
+		//   to resolve the identifier in that case
+	default:
+		// identifiers must be declared elsewhere
+		for _, x := range list {
+			p.resolve(x)
+		}
+	}
+	return list
+}
+
+
+func (p *parser) parseRhsList() []ast.Expr {
+	return p.parseExprList(false)
+}
+
+
 // ----------------------------------------------------------------------------
 // Types
 
@@ -458,31 +504,24 @@ func (p *parser) parseType() ast.Expr {
 }
 
 
-func (p *parser) parseQualifiedIdent() ast.Expr {
+// If the result is an identifier, it is not resolved.
+func (p *parser) parseTypeName() ast.Expr {
 	if p.trace {
-		defer un(trace(p, "QualifiedIdent"))
+		defer un(trace(p, "TypeName"))
 	}
 
 	ident := p.parseIdent()
-	p.resolve(ident)
-	var x ast.Expr = ident
+	// don't resolve ident yet - it may be a parameter or field name
+
 	if p.tok == token.PERIOD {
-		// first identifier is a package identifier
+		// ident is a package name
 		p.next()
+		p.resolve(ident)
 		sel := p.parseIdent()
-		x = &ast.SelectorExpr{x, sel}
+		return &ast.SelectorExpr{ident, sel}
 	}
 
-	return x
-}
-
-
-func (p *parser) parseTypeName() ast.Expr {
-	if p.trace {
-		defer un(trace(p, "TypeName"))
-	}
-
-	return p.parseQualifiedIdent()
+	return ident
 }
 
 
@@ -497,7 +536,7 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
 		len = &ast.Ellipsis{p.pos, nil}
 		p.next()
 	} else if p.tok != token.RBRACK {
-		len = p.parseExpr()
+		len = p.parseRhs()
 	}
 	p.expect(token.RBRACK)
 	elt := p.parseType()
@@ -521,7 +560,7 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
 }
 
 
-func (p *parser) parseFieldDecl() *ast.Field {
+func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 	if p.trace {
 		defer un(trace(p, "FieldDecl"))
 	}
@@ -534,7 +573,7 @@ func (p *parser) parseFieldDecl() *ast.Field {
 	// optional tag
 	var tag *ast.BasicLit
 	if p.tok == token.STRING {
-		tag = &ast.BasicLit{p.pos, p.tok, p.lit()}
+		tag = &ast.BasicLit{p.pos, p.tok, p.lit}
 		p.next()
 	}
 
@@ -546,6 +585,7 @@ func (p *parser) parseFieldDecl() *ast.Field {
 	} else {
 		// ["*"] TypeName (AnonymousField)
 		typ = list[0] // we always have at least one element
+		p.resolve(typ)
 		if n := len(list); n > 1 || !isTypeName(deref(typ)) {
 			pos := typ.Pos()
 			p.errorExpected(pos, "anonymous field")
@@ -555,7 +595,10 @@ func (p *parser) parseFieldDecl() *ast.Field {
 
 	p.expectSemi() // call before accessing p.linecomment
 
-	return &ast.Field{doc, idents, typ, tag, p.lineComment}
+	field := &ast.Field{doc, idents, typ, tag, p.lineComment}
+	p.declare(field, scope, ast.Var, idents...)
+
+	return field
 }
 
 
@@ -566,15 +609,17 @@ func (p *parser) parseStructType() *ast.StructType {
 
 	pos := p.expect(token.STRUCT)
 	lbrace := p.expect(token.LBRACE)
+	scope := ast.NewScope(nil) // struct scope
 	var list []*ast.Field
 	for p.tok == token.IDENT || p.tok == token.MUL || p.tok == token.LPAREN {
 		// a field declaration cannot start with a '(' but we accept
 		// it here for more robust parsing and better error messages
 		// (parseFieldDecl will check and complain if necessary)
-		list = append(list, p.parseFieldDecl())
+		list = append(list, p.parseFieldDecl(scope))
 	}
 	rbrace := p.expect(token.RBRACE)
 
+	// TODO(gri): store struct scope in AST
 	return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
 }
 
@@ -595,7 +640,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
 	if isParam && p.tok == token.ELLIPSIS {
 		pos := p.pos
 		p.next()
-		typ := p.tryType() // don't use parseType so we can provide better error message
+		typ := p.tryIdentOrType(isParam) // don't use parseType so we can provide better error message
 		if typ == nil {
 			p.error(pos, "'...' parameter is missing type")
 			typ = &ast.BadExpr{pos, p.pos}
@@ -605,7 +650,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
 		}
 		return &ast.Ellipsis{pos, typ}
 	}
-	return p.tryType()
+	return p.tryIdentOrType(false)
 }
 
 
@@ -641,6 +686,9 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
 
 	// if we had a list of identifiers, it must be followed by a type
 	typ = p.tryVarType(isParam)
+	if typ != nil {
+		p.resolve(typ)
+	}
 
 	return
 }
@@ -682,6 +730,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
 		// Type { "," Type } (anonymous parameters)
 		params = make([]*ast.Field, len(list))
 		for i, x := range list {
+			p.resolve(x)
 			params[i] = &ast.Field{Type: x}
 		}
 	}
@@ -751,7 +800,7 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
 }
 
 
-func (p *parser) parseMethodSpec() *ast.Field {
+func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
 	if p.trace {
 		defer un(trace(p, "MethodSpec"))
 	}
@@ -759,7 +808,7 @@ func (p *parser) parseMethodSpec() *ast.Field {
 	doc := p.leadComment
 	var idents []*ast.Ident
 	var typ ast.Expr
-	x := p.parseQualifiedIdent()
+	x := p.parseTypeName()
 	if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
 		// method
 		idents = []*ast.Ident{ident}
@@ -772,7 +821,10 @@ func (p *parser) parseMethodSpec() *ast.Field {
 	}
 	p.expectSemi() // call before accessing p.linecomment
 
-	return &ast.Field{doc, idents, typ, nil, p.lineComment}
+	spec := &ast.Field{doc, idents, typ, nil, p.lineComment}
+	p.declare(spec, scope, ast.Fun, idents...)
+
+	return spec
 }
 
 
@@ -783,12 +835,14 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
 
 	pos := p.expect(token.INTERFACE)
 	lbrace := p.expect(token.LBRACE)
+	scope := ast.NewScope(nil) // interface scope
 	var list []*ast.Field
 	for p.tok == token.IDENT {
-		list = append(list, p.parseMethodSpec())
+		list = append(list, p.parseMethodSpec(scope))
 	}
 	rbrace := p.expect(token.RBRACE)
 
+	// TODO(gri): store interface scope in AST
 	return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
 }
 
@@ -832,7 +886,8 @@ func (p *parser) parseChanType() *ast.ChanType {
 }
 
 
-func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
+// If the result is an identifier, it is not resolved.
+func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
 	switch p.tok {
 	case token.IDENT:
 		return p.parseTypeName()
@@ -864,7 +919,13 @@ func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
 }
 
 
-func (p *parser) tryType() ast.Expr { return p.tryRawType(false) }
+func (p *parser) tryType() ast.Expr {
+	typ := p.tryIdentOrType(false)
+	if typ != nil {
+		p.resolve(typ)
+	}
+	return typ
+}
 
 
 // ----------------------------------------------------------------------------
@@ -939,20 +1000,23 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
 
 // parseOperand may return an expression or a raw type (incl. array
 // types of the form [...]T. Callers must verify the result.
+// If lhs is set and the result is an identifier, it is not resolved.
 //
-func (p *parser) parseOperand() ast.Expr {
+func (p *parser) parseOperand(lhs bool) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "Operand"))
 	}
 
 	switch p.tok {
 	case token.IDENT:
-		ident := p.parseIdent()
-		p.resolve(ident)
-		return ident
+		x := p.parseIdent()
+		if !lhs {
+			p.resolve(x)
+		}
+		return x
 
 	case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
-		x := &ast.BasicLit{p.pos, p.tok, p.lit()}
+		x := &ast.BasicLit{p.pos, p.tok, p.lit}
 		p.next()
 		return x
 
@@ -960,7 +1024,7 @@ func (p *parser) parseOperand() ast.Expr {
 		lparen := p.pos
 		p.next()
 		p.exprLev++
-		x := p.parseExpr()
+		x := p.parseRhs()
 		p.exprLev--
 		rparen := p.expect(token.RPAREN)
 		return &ast.ParenExpr{lparen, x, rparen}
@@ -969,9 +1033,11 @@ func (p *parser) parseOperand() ast.Expr {
 		return p.parseFuncTypeOrLit()
 
 	default:
-		t := p.tryRawType(true) // could be type for composite literal or conversion
-		if t != nil {
-			return t
+		if typ := p.tryIdentOrType(true); typ != nil {
+			// could be type for composite literal or conversion
+			_, isIdent := typ.(*ast.Ident)
+			assert(!isIdent, "type cannot be identifier")
+			return typ
 		}
 	}
 
@@ -982,19 +1048,22 @@ func (p *parser) parseOperand() ast.Expr {
 }
 
 
-func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
+func (p *parser) parseSelector(x ast.Expr) ast.Expr {
 	if p.trace {
-		defer un(trace(p, "SelectorOrTypeAssertion"))
+		defer un(trace(p, "Selector"))
 	}
 
-	p.expect(token.PERIOD)
-	if p.tok == token.IDENT {
-		// selector
-		sel := p.parseIdent()
-		return &ast.SelectorExpr{x, sel}
+	sel := p.parseIdent()
+
+	return &ast.SelectorExpr{x, sel}
+}
+
+
+func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
+	if p.trace {
+		defer un(trace(p, "TypeAssertion"))
 	}
 
-	// type assertion
 	p.expect(token.LPAREN)
 	var typ ast.Expr
 	if p.tok == token.TYPE {
@@ -1019,13 +1088,13 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
 	var low, high ast.Expr
 	isSlice := false
 	if p.tok != token.COLON {
-		low = p.parseExpr()
+		low = p.parseRhs()
 	}
 	if p.tok == token.COLON {
 		isSlice = true
 		p.next()
 		if p.tok != token.RBRACK {
-			high = p.parseExpr()
+			high = p.parseRhs()
 		}
 	}
 	p.exprLev--
@@ -1048,7 +1117,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 	var list []ast.Expr
 	var ellipsis token.Pos
 	for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() {
-		list = append(list, p.parseExpr())
+		list = append(list, p.parseRhs())
 		if p.tok == token.ELLIPSIS {
 			ellipsis = p.pos
 			p.next()
@@ -1074,12 +1143,16 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
 		return p.parseLiteralValue(nil)
 	}
 
-	x := p.parseExpr()
-	if keyOk && p.tok == token.COLON {
-		colon := p.pos
-		p.next()
-		x = &ast.KeyValueExpr{x, colon, p.parseElement(false)}
+	x := p.parseExpr(keyOk) // don't resolve if map key
+	if keyOk {
+		if p.tok == token.COLON {
+			colon := p.pos
+			p.next()
+			return &ast.KeyValueExpr{x, colon, p.parseElement(false)}
+		}
+		p.resolve(x) // not a map key
 	}
+
 	return x
 }
 
@@ -1231,23 +1304,47 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
 }
 
 
-func (p *parser) parsePrimaryExpr() ast.Expr {
+// If lhs is set and the result is an identifier, it is not resolved.
+func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "PrimaryExpr"))
 	}
 
-	x := p.parseOperand()
+	x := p.parseOperand(lhs)
 L:
 	for {
 		switch p.tok {
 		case token.PERIOD:
-			x = p.parseSelectorOrTypeAssertion(p.checkExpr(x))
+			p.next()
+			if lhs {
+				p.resolve(x)
+			}
+			switch p.tok {
+			case token.IDENT:
+				x = p.parseSelector(p.checkExpr(x))
+			case token.LPAREN:
+				x = p.parseTypeAssertion(p.checkExpr(x))
+			default:
+				pos := p.pos
+				p.next() // make progress
+				p.errorExpected(pos, "selector or type assertion")
+				x = &ast.BadExpr{pos, p.pos}
+			}
 		case token.LBRACK:
+			if lhs {
+				p.resolve(x)
+			}
 			x = p.parseIndexOrSlice(p.checkExpr(x))
 		case token.LPAREN:
+			if lhs {
+				p.resolve(x)
+			}
 			x = p.parseCallOrConversion(p.checkExprOrType(x))
 		case token.LBRACE:
 			if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
+				if lhs {
+					p.resolve(x)
+				}
 				x = p.parseLiteralValue(x)
 			} else {
 				break L
@@ -1255,13 +1352,15 @@ L:
 		default:
 			break L
 		}
+		lhs = false // no need to try to resolve again
 	}
 
 	return x
 }
 
 
-func (p *parser) parseUnaryExpr() ast.Expr {
+// If lhs is set and the result is an identifier, it is not resolved.
+func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "UnaryExpr"))
 	}
@@ -1270,7 +1369,7 @@ func (p *parser) parseUnaryExpr() ast.Expr {
 	case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.RANGE:
 		pos, op := p.pos, p.tok
 		p.next()
-		x := p.parseUnaryExpr()
+		x := p.parseUnaryExpr(false)
 		return &ast.UnaryExpr{pos, op, p.checkExpr(x)}
 
 	case token.ARROW:
@@ -1283,32 +1382,37 @@ func (p *parser) parseUnaryExpr() ast.Expr {
 			return &ast.ChanType{pos, ast.RECV, value}
 		}
 
-		x := p.parseUnaryExpr()
+		x := p.parseUnaryExpr(false)
 		return &ast.UnaryExpr{pos, token.ARROW, p.checkExpr(x)}
 
 	case token.MUL:
 		// pointer type or unary "*" expression
 		pos := p.pos
 		p.next()
-		x := p.parseUnaryExpr()
+		x := p.parseUnaryExpr(false)
 		return &ast.StarExpr{pos, p.checkExprOrType(x)}
 	}
 
-	return p.parsePrimaryExpr()
+	return p.parsePrimaryExpr(lhs)
 }
 
 
-func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
+// If lhs is set and the result is an identifier, it is not resolved.
+func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "BinaryExpr"))
 	}
 
-	x := p.parseUnaryExpr()
+	x := p.parseUnaryExpr(lhs)
 	for prec := p.tok.Precedence(); prec >= prec1; prec-- {
 		for p.tok.Precedence() == prec {
 			pos, op := p.pos, p.tok
 			p.next()
-			y := p.parseBinaryExpr(prec + 1)
+			if lhs {
+				p.resolve(x)
+				lhs = false
+			}
+			y := p.parseBinaryExpr(false, prec+1)
 			x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)}
 		}
 	}
@@ -1317,14 +1421,20 @@ func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
 }
 
 
+// If lhs is set and the result is an identifier, it is not resolved.
 // TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
 //            should reject when a type/raw type is obviously not allowed
-func (p *parser) parseExpr() ast.Expr {
+func (p *parser) parseExpr(lhs bool) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "Expression"))
 	}
 
-	return p.parseBinaryExpr(token.LowestPrec + 1)
+	return p.parseBinaryExpr(lhs, token.LowestPrec+1)
+}
+
+
+func (p *parser) parseRhs() ast.Expr {
+	return p.parseExpr(false)
 }
 
 
@@ -1336,7 +1446,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
 		defer un(trace(p, "SimpleStmt"))
 	}
 
-	x := p.parseExprList()
+	x := p.parseLhsList()
 
 	switch p.tok {
 	case
@@ -1347,10 +1457,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
 		// assignment statement
 		pos, tok := p.pos, p.tok
 		p.next()
-		y := p.parseExprList()
-		if tok == token.DEFINE {
-			p.shortVarDecl(p.makeIdentList(x))
-		}
+		y := p.parseRhsList()
 		return &ast.AssignStmt{x, pos, tok, y}
 	}
 
@@ -1379,7 +1486,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
 		// send statement
 		arrow := p.pos
 		p.next() // consume "<-"
-		y := p.parseExpr()
+		y := p.parseRhs()
 		return &ast.SendStmt{x[0], arrow, y}
 
 	case token.INC, token.DEC:
@@ -1395,7 +1502,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
 
 
 func (p *parser) parseCallExpr() *ast.CallExpr {
-	x := p.parseExpr()
+	x := p.parseRhs()
 	if call, isCall := x.(*ast.CallExpr); isCall {
 		return call
 	}
@@ -1445,7 +1552,7 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt {
 	p.expect(token.RETURN)
 	var x []ast.Expr
 	if p.tok != token.SEMICOLON && p.tok != token.RBRACE {
-		x = p.parseExprList()
+		x = p.parseRhsList()
 	}
 	p.expectSemi()
 
@@ -1500,12 +1607,12 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
 		p.exprLev = -1
 		if p.tok == token.SEMICOLON {
 			p.next()
-			x = p.parseExpr()
+			x = p.parseRhs()
 		} else {
 			s = p.parseSimpleStmt(false)
 			if p.tok == token.SEMICOLON {
 				p.next()
-				x = p.parseExpr()
+				x = p.parseRhs()
 			} else {
 				x = p.makeExpr(s)
 				s = nil
@@ -1552,7 +1659,7 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
 	if p.tok == token.CASE {
 		p.next()
 		if exprSwitch {
-			list = p.parseExprList()
+			list = p.parseRhsList()
 		} else {
 			list = p.parseTypeList()
 		}
@@ -1639,7 +1746,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
 	var comm ast.Stmt
 	if p.tok == token.CASE {
 		p.next()
-		lhs := p.parseExprList()
+		lhs := p.parseLhsList()
 		if p.tok == token.ARROW {
 			// SendStmt
 			if len(lhs) > 1 {
@@ -1648,7 +1755,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
 			}
 			arrow := p.pos
 			p.next()
-			rhs := p.parseExpr()
+			rhs := p.parseRhs()
 			comm = &ast.SendStmt{lhs[0], arrow, rhs}
 		} else {
 			// RecvStmt
@@ -1663,10 +1770,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
 					lhs = lhs[0:2]
 				}
 				p.next()
-				rhs = p.parseExpr()
-				if tok == token.DEFINE {
-					p.shortVarDecl(p.makeIdentList(lhs))
-				}
+				rhs = p.parseRhs()
 			} else {
 				// rhs must be single receive operation
 				if len(lhs) > 1 {
@@ -1866,14 +1970,18 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 
 	var path *ast.BasicLit
 	if p.tok == token.STRING {
-		path = &ast.BasicLit{p.pos, p.tok, p.lit()}
+		path = &ast.BasicLit{p.pos, p.tok, p.lit}
 		p.next()
 	} else {
 		p.expect(token.STRING) // use expect() error handling
 	}
 	p.expectSemi() // call before accessing p.linecomment
 
-	return &ast.ImportSpec{doc, ident, path, p.lineComment}
+	// collect imports
+	spec := &ast.ImportSpec{doc, ident, path, p.lineComment}
+	p.imports = append(p.imports, spec)
+
+	return spec
 }
 
 
@@ -1887,7 +1995,7 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
 	var values []ast.Expr
 	if typ != nil || p.tok == token.ASSIGN || iota == 0 {
 		p.expect(token.ASSIGN)
-		values = p.parseExprList()
+		values = p.parseRhsList()
 	}
 	p.expectSemi() // call before accessing p.linecomment
 
@@ -1932,7 +2040,7 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
 	var values []ast.Expr
 	if typ == nil || p.tok == token.ASSIGN {
 		p.expect(token.ASSIGN)
-		values = p.parseExprList()
+		values = p.parseRhsList()
 	}
 	p.expectSemi() // call before accessing p.linecomment
 
@@ -2120,20 +2228,20 @@ func (p *parser) parseFile() *ast.File {
 		}
 	}
 
-	if p.topScope != p.pkgScope {
-		panic("internal error: imbalanced scopes")
-	}
+	assert(p.topScope == p.pkgScope, "imbalanced scopes")
 
 	// resolve global identifiers within the same file
 	i := 0
 	for _, ident := range p.unresolved {
 		// i <= index for current ident
-		ident.Obj = p.pkgScope.Lookup(ident.Name)
+		assert(ident.Obj == unresolved, "object already resolved")
+		ident.Obj = p.pkgScope.Lookup(ident.Name) // also removes unresolved sentinel
 		if ident.Obj == nil {
 			p.unresolved[i] = ident
 			i++
 		}
 	}
 
-	return &ast.File{doc, pos, ident, decls, p.pkgScope, p.unresolved[0:i], p.comments}
+	// TODO(gri): store p.imports in AST
+	return &ast.File{doc, pos, ident, decls, p.pkgScope, p.imports, p.unresolved[0:i], p.comments}
 }
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go
index 2238b6bedc8..0b3b6621e6c 100644
--- a/libgo/go/go/printer/nodes.go
+++ b/libgo/go/go/printer/nodes.go
@@ -160,19 +160,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
 	// the first linebreak is always a formfeed since this section must not
 	// depend on any previous formatting
 	prevBreak := -1 // index of last expression that was followed by a linebreak
-	linebreakMin := 1
-	if mode&periodSep != 0 {
-		// Make fragments like
-		//
-		// a.Bar(1,
-		//   2).Foo
-		//
-		// format correctly (a linebreak shouldn't be added before Foo) when
-		// doing period-separated expr lists by setting minimum linebreak to 0
-		// lines for them.
-		linebreakMin = 0
-	}
-	if prev.IsValid() && prev.Line < line && p.linebreak(line, linebreakMin, ws, true) {
+	if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) {
 		ws = ignore
 		*multiLine = true
 		prevBreak = 0
@@ -237,7 +225,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
 				// lines are broken using newlines so comments remain aligned
 				// unless forceFF is set or there are multiple expressions on
 				// the same line in which case formfeed is used
-				if p.linebreak(line, linebreakMin, ws, useFF || prevBreak+1 < i) {
+				if p.linebreak(line, 0, ws, useFF || prevBreak+1 < i) {
 					ws = ignore
 					*multiLine = true
 					prevBreak = i
@@ -363,7 +351,7 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
 
 
 func (p *printer) setLineComment(text string) {
-	p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, []byte(text)}}})
+	p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}})
 }
 
 
@@ -527,7 +515,7 @@ func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
 		}
 
 	case *ast.StarExpr:
-		if e.Op.String() == "/" {
+		if e.Op == token.QUO { // `*/`
 			maxProblem = 5
 		}
 
diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go
index a43e4a12c77..697a83fa866 100644
--- a/libgo/go/go/printer/printer.go
+++ b/libgo/go/go/printer/printer.go
@@ -34,12 +34,6 @@ const (
 )
 
 
-const (
-	esc2 = '\xfe'                        // an escape byte that cannot occur in regular UTF-8
-	_    = 1 / (esc2 - tabwriter.Escape) // cause compiler error if esc2 == tabwriter.Escape
-)
-
-
 var (
 	esc       = []byte{tabwriter.Escape}
 	htab      = []byte{'\t'}
@@ -81,8 +75,9 @@ type printer struct {
 	mode    pmode       // current printer mode
 	lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace)
 
-	// Buffered whitespace
-	buffer []whiteSpace
+	// Reused buffers
+	wsbuf  []whiteSpace // delayed white space
+	litbuf bytes.Buffer // for creation of escaped literals and comments
 
 	// The (possibly estimated) position in the generated output;
 	// in AST space (i.e., pos is set whenever a token position is
@@ -109,7 +104,7 @@ func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeS
 	p.Config = *cfg
 	p.fset = fset
 	p.errors = make(chan os.Error)
-	p.buffer = make([]whiteSpace, 0, 16) // whitespace sequences are short
+	p.wsbuf = make([]whiteSpace, 0, 16) // whitespace sequences are short
 	p.nodeSizes = nodeSizes
 }
 
@@ -123,6 +118,20 @@ func (p *printer) internalError(msg ...interface{}) {
 }
 
 
+// escape escapes string s by bracketing it with tabwriter.Escape.
+// Escaped strings pass through tabwriter unchanged. (Note that
+// valid Go programs cannot contain tabwriter.Escape bytes since
+// they do not appear in legal UTF-8 sequences).
+//
+func (p *printer) escape(s string) string {
+	p.litbuf.Reset()
+	p.litbuf.WriteByte(tabwriter.Escape)
+	p.litbuf.WriteString(s)
+	p.litbuf.WriteByte(tabwriter.Escape)
+	return p.litbuf.String()
+}
+
+
 // nlines returns the adjusted number of linebreaks given the desired number
 // of breaks n such that min <= result <= max where max depends on the current
 // nesting level.
@@ -230,7 +239,7 @@ func (p *printer) writeNewlines(n int, useFF bool) {
 // source text. writeItem updates p.last to the position immediately following
 // the data.
 //
-func (p *printer) writeItem(pos token.Position, data []byte) {
+func (p *printer) writeItem(pos token.Position, data string) {
 	if pos.IsValid() {
 		// continue with previous position if we don't have a valid pos
 		if p.last.IsValid() && p.last.Filename != pos.Filename {
@@ -239,7 +248,7 @@ func (p *printer) writeItem(pos token.Position, data []byte) {
 			// e.g., the result of ast.MergePackageFiles)
 			p.indent = 0
 			p.mode = 0
-			p.buffer = p.buffer[0:0]
+			p.wsbuf = p.wsbuf[0:0]
 		}
 		p.pos = pos
 	}
@@ -248,7 +257,7 @@ func (p *printer) writeItem(pos token.Position, data []byte) {
 		_, filename := filepath.Split(pos.Filename)
 		p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, pos.Column)))
 	}
-	p.write(data)
+	p.write([]byte(data))
 	p.last = p.pos
 }
 
@@ -280,11 +289,11 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment
 		if prev == nil {
 			// first comment of a comment group
 			j := 0
-			for i, ch := range p.buffer {
+			for i, ch := range p.wsbuf {
 				switch ch {
 				case blank:
 					// ignore any blanks before a comment
-					p.buffer[i] = ignore
+					p.wsbuf[i] = ignore
 					continue
 				case vtab:
 					// respect existing tabs - important
@@ -318,11 +327,11 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment
 		if prev == nil {
 			// first comment of a comment group
 			j := 0
-			for i, ch := range p.buffer {
+			for i, ch := range p.wsbuf {
 				switch ch {
 				case blank, vtab:
 					// ignore any horizontal whitespace before line breaks
-					p.buffer[i] = ignore
+					p.wsbuf[i] = ignore
 					continue
 				case indent:
 					// apply pending indentation
@@ -339,7 +348,7 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment
 					}
 				case newline, formfeed:
 					// TODO(gri): may want to keep formfeed info in some cases
-					p.buffer[i] = ignore
+					p.wsbuf[i] = ignore
 				}
 				j = i
 				break
@@ -360,12 +369,8 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment
 }
 
 
-func (p *printer) writeCommentLine(comment *ast.Comment, pos token.Position, line []byte) {
-	// line must pass through unchanged, bracket it with tabwriter.Escape
-	line = bytes.Join([][]byte{esc, line, esc}, nil)
-	p.writeItem(pos, line)
-}
-
+// TODO(gri): It should be possible to convert the code below from using
+//            []byte to string and in the process eliminate some conversions.
 
 // Split comment text into lines
 func split(text []byte) [][]byte {
@@ -546,13 +551,13 @@ func (p *printer) writeComment(comment *ast.Comment) {
 
 	// shortcut common case of //-style comments
 	if text[1] == '/' {
-		p.writeCommentLine(comment, p.fset.Position(comment.Pos()), text)
+		p.writeItem(p.fset.Position(comment.Pos()), p.escape(text))
 		return
 	}
 
 	// for /*-style comments, print line by line and let the
 	// write function take care of the proper indentation
-	lines := split(text)
+	lines := split([]byte(text))
 	stripCommonPrefix(lines)
 
 	// write comment lines, separated by formfeed,
@@ -565,7 +570,7 @@ func (p *printer) writeComment(comment *ast.Comment) {
 			pos = p.pos
 		}
 		if len(line) > 0 {
-			p.writeCommentLine(comment, pos, line)
+			p.writeItem(pos, p.escape(string(line)))
 		}
 	}
 }
@@ -578,11 +583,11 @@ func (p *printer) writeComment(comment *ast.Comment) {
 // formfeed was dropped from the whitespace buffer.
 //
 func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
-	for i, ch := range p.buffer {
+	for i, ch := range p.wsbuf {
 		switch ch {
 		case blank, vtab:
 			// ignore trailing whitespace
-			p.buffer[i] = ignore
+			p.wsbuf[i] = ignore
 		case indent, unindent:
 			// don't loose indentation information
 		case newline, formfeed:
@@ -594,11 +599,11 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
 				if ch == formfeed {
 					droppedFF = true
 				}
-				p.buffer[i] = ignore
+				p.wsbuf[i] = ignore
 			}
 		}
 	}
-	p.writeWhitespace(len(p.buffer))
+	p.writeWhitespace(len(p.wsbuf))
 
 	// make sure we have a line break
 	if needsLinebreak {
@@ -652,7 +657,7 @@ func (p *printer) writeWhitespace(n int) {
 	// write entries
 	var data [1]byte
 	for i := 0; i < n; i++ {
-		switch ch := p.buffer[i]; ch {
+		switch ch := p.wsbuf[i]; ch {
 		case ignore:
 			// ignore!
 		case indent:
@@ -670,13 +675,13 @@ func (p *printer) writeWhitespace(n int) {
 			// the line break and the label, the unindent is not
 			// part of the comment whitespace prefix and the comment
 			// will be positioned correctly indented.
-			if i+1 < n && p.buffer[i+1] == unindent {
+			if i+1 < n && p.wsbuf[i+1] == unindent {
 				// Use a formfeed to terminate the current section.
 				// Otherwise, a long label name on the next line leading
 				// to a wide column may increase the indentation column
 				// of lines before the label; effectively leading to wrong
 				// indentation.
-				p.buffer[i], p.buffer[i+1] = unindent, formfeed
+				p.wsbuf[i], p.wsbuf[i+1] = unindent, formfeed
 				i-- // do it again
 				continue
 			}
@@ -689,11 +694,11 @@ func (p *printer) writeWhitespace(n int) {
 
 	// shift remaining entries down
 	i := 0
-	for ; n < len(p.buffer); n++ {
-		p.buffer[i] = p.buffer[n]
+	for ; n < len(p.wsbuf); n++ {
+		p.wsbuf[i] = p.wsbuf[n]
 		i++
 	}
-	p.buffer = p.buffer[0:i]
+	p.wsbuf = p.wsbuf[0:i]
 }
 
 
@@ -734,7 +739,7 @@ func mayCombine(prev token.Token, next byte) (b bool) {
 func (p *printer) print(args ...interface{}) {
 	for _, f := range args {
 		next := p.pos // estimated position of next item
-		var data []byte
+		var data string
 		var tok token.Token
 
 		switch x := f.(type) {
@@ -748,42 +753,22 @@ func (p *printer) print(args ...interface{}) {
 				// LabeledStmt)
 				break
 			}
-			i := len(p.buffer)
-			if i == cap(p.buffer) {
+			i := len(p.wsbuf)
+			if i == cap(p.wsbuf) {
 				// Whitespace sequences are very short so this should
 				// never happen. Handle gracefully (but possibly with
 				// bad comment placement) if it does happen.
 				p.writeWhitespace(i)
 				i = 0
 			}
-			p.buffer = p.buffer[0 : i+1]
-			p.buffer[i] = x
+			p.wsbuf = p.wsbuf[0 : i+1]
+			p.wsbuf[i] = x
 		case *ast.Ident:
-			data = []byte(x.Name)
+			data = x.Name
 			tok = token.IDENT
 		case *ast.BasicLit:
-			// escape all literals so they pass through unchanged
-			// (note that valid Go programs cannot contain
-			// tabwriter.Escape bytes since they do not appear in
-			// legal UTF-8 sequences)
-			data = make([]byte, 0, len(x.Value)+2)
-			data = append(data, tabwriter.Escape)
-			data = append(data, x.Value...)
-			data = append(data, tabwriter.Escape)
+			data = p.escape(x.Value)
 			tok = x.Kind
-			// If we have a raw string that spans multiple lines and
-			// the opening quote (`) is on a line preceded only by
-			// indentation, we don't want to write that indentation
-			// because the following lines of the raw string are not
-			// indented. It's easiest to correct the output at the end
-			// via the trimmer (because of the complex handling of
-			// white space).
-			// Mark multi-line raw strings by replacing the opening
-			// quote with esc2 and have the trimmer take care of fixing
-			// it up. (Do this _after_ making a copy of data!)
-			if data[1] == '`' && bytes.IndexByte(data, '\n') > 0 {
-				data[1] = esc2
-			}
 		case token.Token:
 			s := x.String()
 			if mayCombine(p.lastTok, s[0]) {
@@ -793,13 +778,13 @@ func (p *printer) print(args ...interface{}) {
 				// (except for token.INT followed by a '.' this
 				// should never happen because it is taken care
 				// of via binary expression formatting)
-				if len(p.buffer) != 0 {
+				if len(p.wsbuf) != 0 {
 					p.internalError("whitespace buffer not empty")
 				}
-				p.buffer = p.buffer[0:1]
-				p.buffer[0] = ' '
+				p.wsbuf = p.wsbuf[0:1]
+				p.wsbuf[0] = ' '
 			}
-			data = []byte(s)
+			data = s
 			tok = x
 		case token.Pos:
 			if x.IsValid() {
@@ -813,7 +798,7 @@ func (p *printer) print(args ...interface{}) {
 		p.lastTok = tok
 		p.pos = next
 
-		if data != nil {
+		if data != "" {
 			droppedFF := p.flush(next, tok)
 
 			// intersperse extra newlines if present in the source
@@ -848,7 +833,7 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
 		droppedFF = p.intersperseComments(next, tok)
 	} else {
 		// otherwise, write any leftover whitespace
-		p.writeWhitespace(len(p.buffer))
+		p.writeWhitespace(len(p.wsbuf))
 	}
 	return
 }
@@ -864,10 +849,9 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
 // through unchanged.
 //
 type trimmer struct {
-	output  io.Writer
-	state   int
-	space   bytes.Buffer
-	hasText bool
+	output io.Writer
+	state  int
+	space  bytes.Buffer
 }
 
 
@@ -875,15 +859,11 @@ type trimmer struct {
 // It can be in one of the following states:
 const (
 	inSpace  = iota // inside space
-	atEscape        // inside space and the last char was an opening tabwriter.Escape
 	inEscape        // inside text bracketed by tabwriter.Escapes
 	inText          // inside text
 )
 
 
-var backquote = []byte{'`'}
-
-
 // Design note: It is tempting to eliminate extra blanks occurring in
 //              whitespace in this function as it could simplify some
 //              of the blanks logic in the node printing functions.
@@ -892,9 +872,8 @@ var backquote = []byte{'`'}
 
 func (p *trimmer) Write(data []byte) (n int, err os.Error) {
 	// invariants:
-	// p.state == inSpace, atEscape:
+	// p.state == inSpace:
 	//	p.space is unwritten
-	//	p.hasText indicates if there is any text on this line
 	// p.state == inEscape, inText:
 	//	data[m:n] is unwritten
 	m := 0
@@ -911,32 +890,20 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
 			case '\n', '\f':
 				p.space.Reset()                        // discard trailing space
 				_, err = p.output.Write(newlines[0:1]) // write newline
-				p.hasText = false
 			case tabwriter.Escape:
-				p.state = atEscape
+				_, err = p.output.Write(p.space.Bytes())
+				p.state = inEscape
+				m = n + 1 // +1: skip tabwriter.Escape
 			default:
 				_, err = p.output.Write(p.space.Bytes())
 				p.state = inText
 				m = n
 			}
-		case atEscape:
-			// discard indentation if we have a multi-line raw string
-			// (see printer.print for details)
-			if b != esc2 || p.hasText {
-				_, err = p.output.Write(p.space.Bytes())
-			}
-			p.state = inEscape
-			m = n
-			if b == esc2 {
-				_, err = p.output.Write(backquote) // convert back
-				m++
-			}
 		case inEscape:
 			if b == tabwriter.Escape {
 				_, err = p.output.Write(data[m:n])
 				p.state = inSpace
 				p.space.Reset()
-				p.hasText = true
 			}
 		case inText:
 			switch b {
@@ -945,19 +912,18 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
 				p.state = inSpace
 				p.space.Reset()
 				p.space.WriteByte(b) // WriteByte returns no errors
-				p.hasText = true
 			case '\n', '\f':
 				_, err = p.output.Write(data[m:n])
 				p.state = inSpace
 				p.space.Reset()
 				_, err = p.output.Write(newlines[0:1]) // write newline
-				p.hasText = false
 			case tabwriter.Escape:
 				_, err = p.output.Write(data[m:n])
-				p.state = atEscape
-				p.space.Reset()
-				p.hasText = true
+				p.state = inEscape
+				m = n + 1 // +1: skip tabwriter.Escape
 			}
+		default:
+			panic("unreachable")
 		}
 		if err != nil {
 			return
@@ -970,7 +936,6 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
 		_, err = p.output.Write(data[m:n])
 		p.state = inSpace
 		p.space.Reset()
-		p.hasText = true
 	}
 
 	return
diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go
index 3ff087e2993..090f92af181 100644
--- a/libgo/go/go/printer/printer_test.go
+++ b/libgo/go/go/printer/printer_test.go
@@ -114,7 +114,7 @@ func check(t *testing.T, source, golden string, mode checkMode) {
 	// start a timer to produce a time-out signal
 	tc := make(chan int)
 	go func() {
-		time.Sleep(20e9) // plenty of a safety margin, even for very slow machines
+		time.Sleep(10e9) // plenty of a safety margin, even for very slow machines
 		tc <- 0
 	}()
 
@@ -156,12 +156,15 @@ var data = []entry{
 
 
 func TestFiles(t *testing.T) {
-	for _, e := range data {
+	for i, e := range data {
 		source := filepath.Join(dataDir, e.source)
 		golden := filepath.Join(dataDir, e.golden)
 		check(t, source, golden, e.mode)
 		// TODO(gri) check that golden is idempotent
-		//check(t, golden, golden, e.mode);
+		//check(t, golden, golden, e.mode)
+		if testing.Short() && i >= 3 {
+			break
+		}
 	}
 }
 
diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden
index 314d3213c74..c1a7e970b45 100644
--- a/libgo/go/go/printer/testdata/expressions.golden
+++ b/libgo/go/go/printer/testdata/expressions.golden
@@ -253,8 +253,8 @@ bar`
 	var _ = ``
 	var _ = `foo`
 	var _ =
-	// the next line should not be indented
-`foo
+	// the next line should remain indented
+	`foo
 bar`
 
 	var _ =	// comment
@@ -262,8 +262,8 @@ bar`
 	var _ =	// comment
 	`foo`
 	var _ =	// comment
-	// the next line should not be indented
-`foo
+	// the next line should remain indented
+	`foo
 bar`
 
 	var _ = /* comment */ ``
@@ -276,12 +276,12 @@ bar`
 	var _ =	/* comment */
 	`foo`
 	var _ =	/* comment */
-	// the next line should not be indented
-`foo
+	// the next line should remain indented
+	`foo
 bar`
 
 	var board = []int(
-`...........
+		`...........
 ...........
 ....●●●....
 ....●●●....
@@ -296,8 +296,8 @@ bar`
 
 	var state = S{
 		"foo",
-		// the next line should not be indented
-`...........
+		// the next line should remain indented
+		`...........
 ...........
 ....●●●....
 ....●●●....
@@ -619,3 +619,13 @@ func _() {
 		b.(T).
 		c
 }
+
+
+// Don't introduce extra newlines in strangely formatted expression lists.
+func f() {
+	// os.Open parameters should remain on two lines
+	if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
+		os.O_TRUNC,0666); err != nil {
+		log.Fatal(err)
+	}
+}
diff --git a/libgo/go/go/printer/testdata/expressions.input b/libgo/go/go/printer/testdata/expressions.input
index cac22af4313..b87381198e4 100644
--- a/libgo/go/go/printer/testdata/expressions.input
+++ b/libgo/go/go/printer/testdata/expressions.input
@@ -256,7 +256,7 @@ var _ =
 var _ =
 	`foo`
 var _ =
-	// the next line should not be indented
+	// the next line should remain indented
 	`foo
 bar`
 
@@ -266,7 +266,7 @@ bar`
 	var _ = // comment
 		`foo`
 	var _ = // comment
-		// the next line should not be indented
+		// the next line should remain indented
 		`foo
 bar`
 
@@ -282,7 +282,7 @@ bar`
 	var _ = /* comment */
 		`foo`
 	var _ = /* comment */
-		// the next line should not be indented
+		// the next line should remain indented
 		`foo
 bar`
 
@@ -304,7 +304,7 @@ var board = []int(
 
 	var state = S{
 		"foo",
-		// the next line should not be indented
+		// the next line should remain indented
 		`...........
 ...........
 ....●●●....
@@ -625,3 +625,13 @@ baz()
 	(T).
 	c
 }
+
+
+// Don't introduce extra newlines in strangely formatted expression lists.
+func f() {
+	// os.Open parameters should remain on two lines
+	if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
+		os.O_TRUNC, 0666); err != nil {
+	    log.Fatal(err)
+	}
+}
diff --git a/libgo/go/go/printer/testdata/expressions.raw b/libgo/go/go/printer/testdata/expressions.raw
index f22ceeb476f..735cd943e69 100644
--- a/libgo/go/go/printer/testdata/expressions.raw
+++ b/libgo/go/go/printer/testdata/expressions.raw
@@ -239,7 +239,8 @@ func _() {
 	_ = `foo
 		bar`
 	_ = `three spaces before the end of the line starting here:   
-they must not be removed`}
+they must not be removed`
+}
 
 
 func _() {
@@ -252,8 +253,8 @@ bar`
 	var _ = ``
 	var _ = `foo`
 	var _ =
-	// the next line should not be indented
-`foo
+	// the next line should remain indented
+	`foo
 bar`
 
 	var _ =	// comment
@@ -261,8 +262,8 @@ bar`
 	var _ =	// comment
 	`foo`
 	var _ =	// comment
-	// the next line should not be indented
-`foo
+	// the next line should remain indented
+	`foo
 bar`
 
 	var _ = /* comment */ ``
@@ -275,12 +276,12 @@ bar`
 	var _ =	/* comment */
 	`foo`
 	var _ =	/* comment */
-	// the next line should not be indented
-`foo
+	// the next line should remain indented
+	`foo
 bar`
 
 	var board = []int(
-`...........
+		`...........
 ...........
 ....●●●....
 ....●●●....
@@ -295,8 +296,8 @@ bar`
 
 	var state = S{
 		"foo",
-		// the next line should not be indented
-`...........
+		// the next line should remain indented
+		`...........
 ...........
 ....●●●....
 ....●●●....
@@ -618,3 +619,13 @@ func _() {
 		b.(T).
 		c
 }
+
+
+// Don't introduce extra newlines in strangely formatted expression lists.
+func f() {
+	// os.Open parameters should remain on two lines
+	if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
+		os.O_TRUNC,0666); err != nil {
+		log.Fatal(err)
+	}
+}
diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go
index 59fed9dffc6..2f949ad2568 100644
--- a/libgo/go/go/scanner/scanner.go
+++ b/libgo/go/go/scanner/scanner.go
@@ -538,14 +538,12 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Toke
 }
 
 
-var newline = []byte{'\n'}
-
-// Scan scans the next token and returns the token position pos,
-// the token tok, and the literal text lit corresponding to the
+// Scan scans the next token and returns the token position,
+// the token, and the literal string corresponding to the
 // token. The source end is indicated by token.EOF.
 //
 // If the returned token is token.SEMICOLON, the corresponding
-// literal value is ";" if the semicolon was present in the source,
+// literal string is ";" if the semicolon was present in the source,
 // and "\n" if the semicolon was inserted because of a newline or
 // at EOF.
 //
@@ -560,7 +558,7 @@ var newline = []byte{'\n'}
 // set with Init. Token positions are relative to that file
 // and thus relative to the file set.
 //
-func (S *Scanner) Scan() (token.Pos, token.Token, []byte) {
+func (S *Scanner) Scan() (token.Pos, token.Token, string) {
 scanAgain:
 	S.skipWhitespace()
 
@@ -586,7 +584,7 @@ scanAgain:
 		case -1:
 			if S.insertSemi {
 				S.insertSemi = false // EOF consumed
-				return S.file.Pos(offs), token.SEMICOLON, newline
+				return S.file.Pos(offs), token.SEMICOLON, "\n"
 			}
 			tok = token.EOF
 		case '\n':
@@ -594,7 +592,7 @@ scanAgain:
 			// set in the first place and exited early
 			// from S.skipWhitespace()
 			S.insertSemi = false // newline consumed
-			return S.file.Pos(offs), token.SEMICOLON, newline
+			return S.file.Pos(offs), token.SEMICOLON, "\n"
 		case '"':
 			insertSemi = true
 			tok = token.STRING
@@ -662,7 +660,7 @@ scanAgain:
 					S.offset = offs
 					S.rdOffset = offs + 1
 					S.insertSemi = false // newline consumed
-					return S.file.Pos(offs), token.SEMICOLON, newline
+					return S.file.Pos(offs), token.SEMICOLON, "\n"
 				}
 				S.scanComment()
 				if S.mode&ScanComments == 0 {
@@ -711,5 +709,9 @@ scanAgain:
 	if S.mode&InsertSemis != 0 {
 		S.insertSemi = insertSemi
 	}
-	return S.file.Pos(offs), tok, S.src[offs:S.offset]
+
+	// TODO(gri): The scanner API should change such that the literal string
+	//            is only valid if an actual literal was scanned. This will
+	//            permit a more efficient implementation.
+	return S.file.Pos(offs), tok, string(S.src[offs:S.offset])
 }
diff --git a/libgo/go/go/scanner/scanner_test.go b/libgo/go/go/scanner/scanner_test.go
index 93f34581b7f..8afb00ee5bc 100644
--- a/libgo/go/go/scanner/scanner_test.go
+++ b/libgo/go/go/scanner/scanner_test.go
@@ -234,12 +234,11 @@ func TestScan(t *testing.T) {
 	index := 0
 	epos := token.Position{"", 0, 1, 1} // expected position
 	for {
-		pos, tok, litb := s.Scan()
+		pos, tok, lit := s.Scan()
 		e := elt{token.EOF, "", special}
 		if index < len(tokens) {
 			e = tokens[index]
 		}
-		lit := string(litb)
 		if tok == token.EOF {
 			lit = ""
 			epos.Line = src_linecount
@@ -257,7 +256,7 @@ func TestScan(t *testing.T) {
 		}
 		epos.Offset += len(lit) + len(whitespace)
 		epos.Line += newlineCount(lit) + whitespace_linecount
-		if tok == token.COMMENT && litb[1] == '/' {
+		if tok == token.COMMENT && lit[1] == '/' {
 			// correct for unaccounted '/n' in //-style comment
 			epos.Offset++
 			epos.Line++
@@ -292,7 +291,7 @@ func checkSemi(t *testing.T, line string, mode uint) {
 			semiPos.Column++
 			pos, tok, lit = S.Scan()
 			if tok == token.SEMICOLON {
-				if string(lit) != semiLit {
+				if lit != semiLit {
 					t.Errorf(`bad literal for %q: got %q, expected %q`, line, lit, semiLit)
 				}
 				checkPos(t, line, pos, semiPos)
@@ -493,7 +492,7 @@ func TestLineComments(t *testing.T) {
 	for _, s := range segments {
 		p, _, lit := S.Scan()
 		pos := file.Position(p)
-		checkPos(t, string(lit), p, token.Position{s.filename, pos.Offset, s.line, pos.Column})
+		checkPos(t, lit, p, token.Position{s.filename, pos.Offset, s.line, pos.Column})
 	}
 
 	if S.ErrorCount != 0 {
@@ -547,10 +546,10 @@ func TestIllegalChars(t *testing.T) {
 	for offs, ch := range src {
 		pos, tok, lit := s.Scan()
 		if poffs := file.Offset(pos); poffs != offs {
-			t.Errorf("bad position for %s: got %d, expected %d", string(lit), poffs, offs)
+			t.Errorf("bad position for %s: got %d, expected %d", lit, poffs, offs)
 		}
-		if tok == token.ILLEGAL && string(lit) != string(ch) {
-			t.Errorf("bad token: got %s, expected %s", string(lit), string(ch))
+		if tok == token.ILLEGAL && lit != string(ch) {
+			t.Errorf("bad token: got %s, expected %s", lit, string(ch))
 		}
 	}
 
diff --git a/libgo/go/go/token/token.go b/libgo/go/go/token/token.go
index 2a2d3ecc4fb..a5f21df168e 100644
--- a/libgo/go/go/token/token.go
+++ b/libgo/go/go/token/token.go
@@ -126,10 +126,7 @@ const (
 )
 
 
-// At the moment we have no array literal syntax that lets us describe
-// the index for each element - use a map for now to make sure they are
-// in sync.
-var tokens = map[Token]string{
+var tokens = [...]string{
 	ILLEGAL: "ILLEGAL",
 
 	EOF:     "EOF",
@@ -237,10 +234,14 @@ var tokens = map[Token]string{
 // constant name (e.g. for the token IDENT, the string is "IDENT").
 //
 func (tok Token) String() string {
-	if str, exists := tokens[tok]; exists {
-		return str
+	s := ""
+	if 0 <= tok && tok < Token(len(tokens)) {
+		s = tokens[tok]
 	}
-	return "token(" + strconv.Itoa(int(tok)) + ")"
+	if s == "" {
+		s = "token(" + strconv.Itoa(int(tok)) + ")"
+	}
+	return s
 }
 
 
diff --git a/libgo/go/go/typechecker/scope.go b/libgo/go/go/typechecker/scope.go
index bd24f4ca42d..a4bee6e6962 100644
--- a/libgo/go/go/typechecker/scope.go
+++ b/libgo/go/go/typechecker/scope.go
@@ -33,7 +33,7 @@ func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast
 	//obj.N = n
 	name.Obj = obj
 	if name.Name != "_" {
-		if alt := scope.Insert(obj); alt != obj {
+		if alt := scope.Insert(obj); alt != nil {
 			tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, tc.fset.Position(alt.Pos()).String())
 		}
 	}
diff --git a/libgo/go/go/typechecker/typechecker.go b/libgo/go/go/typechecker/typechecker.go
index 4fc5647f0d5..b5e695d973a 100644
--- a/libgo/go/go/typechecker/typechecker.go
+++ b/libgo/go/go/typechecker/typechecker.go
@@ -53,7 +53,7 @@ func CheckPackage(fset *token.FileSet, pkg *ast.Package, importer Importer) os.E
 //
 func CheckFile(fset *token.FileSet, file *ast.File, importer Importer) os.Error {
 	// create a single-file dummy package
-	pkg := &ast.Package{file.Name.Name, nil, map[string]*ast.File{fset.Position(file.Name.NamePos).Filename: file}}
+	pkg := &ast.Package{file.Name.Name, nil, nil, map[string]*ast.File{fset.Position(file.Name.NamePos).Filename: file}}
 	return CheckPackage(fset, pkg, importer)
 }
 
@@ -327,8 +327,8 @@ func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) {
 	if ftype != nil {
 		for _, par := range ftype.Params.Objects {
 			if par.Name != "_" {
-				obj := tc.topScope.Insert(par)
-				assert(obj == par) // ftype has no double declarations
+				alt := tc.topScope.Insert(par)
+				assert(alt == nil) // ftype has no double declarations
 			}
 		}
 	}
diff --git a/libgo/go/go/typechecker/typechecker_test.go b/libgo/go/go/typechecker/typechecker_test.go
index 3988ff1680b..d16e0692180 100644
--- a/libgo/go/go/typechecker/typechecker_test.go
+++ b/libgo/go/go/typechecker/typechecker_test.go
@@ -78,7 +78,7 @@ func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
 			case token.EOF:
 				break loop
 			case token.COMMENT:
-				s := errRx.FindSubmatch(lit)
+				s := errRx.FindStringSubmatch(lit)
 				if len(s) == 2 {
 					list = append(list, &scanner.Error{fset.Position(prev), string(s[1])})
 				}
diff --git a/libgo/go/go/typechecker/universe.go b/libgo/go/go/typechecker/universe.go
index cf4434993e1..abc8bbbd49c 100644
--- a/libgo/go/go/typechecker/universe.go
+++ b/libgo/go/go/typechecker/universe.go
@@ -14,7 +14,7 @@ var Universe *ast.Scope
 
 func def(obj *ast.Object) {
 	alt := Universe.Insert(obj)
-	if alt != obj {
+	if alt != nil {
 		panic("object declared twice")
 	}
 }
diff --git a/libgo/go/gob/type.go b/libgo/go/gob/type.go
index fc620f5c7c1..305d41980a5 100644
--- a/libgo/go/gob/type.go
+++ b/libgo/go/gob/type.go
@@ -407,7 +407,7 @@ func (s *structType) string() string { return s.safeString(make(map[typeId]bool)
 func newStructType(name string) *structType {
 	s := &structType{CommonType{Name: name}, nil}
 	// For historical reasons we set the id here rather than init.
-	// Se the comment in newTypeObject for details.
+	// See the comment in newTypeObject for details.
 	setTypeId(s)
 	return s
 }
@@ -545,7 +545,7 @@ func getBaseType(name string, rt reflect.Type) (gobType, os.Error) {
 // getType returns the Gob type describing the given reflect.Type.
 // Should be called only when handling GobEncoders/Decoders,
 // which may be pointers.  All other types are handled through the
-//  base type, never a pointer.
+// base type, never a pointer.
 // typeLock must be held.
 func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error) {
 	typ, present := types[rt]
@@ -561,7 +561,7 @@ func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.Error)
 
 func checkId(want, got typeId) {
 	if want != got {
-		fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(want), int(got))
+		fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(got), int(want))
 		panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string())
 	}
 }
diff --git a/libgo/go/http/fs.go b/libgo/go/http/fs.go
index 4ad680ccc31..8b5c4770c49 100644
--- a/libgo/go/http/fs.go
+++ b/libgo/go/http/fs.go
@@ -154,7 +154,10 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
 	// handle Content-Range header.
 	// TODO(adg): handle multiple ranges
 	ranges, err := parseRange(r.Header.Get("Range"), size)
-	if err != nil || len(ranges) > 1 {
+	if err == nil && len(ranges) > 1 {
+		err = os.ErrorString("multiple ranges not supported")
+	}
+	if err != nil {
 		Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
 		return
 	}
diff --git a/libgo/go/http/pprof/pprof.go b/libgo/go/http/pprof/pprof.go
index 0bac26687d7..bc79e218320 100644
--- a/libgo/go/http/pprof/pprof.go
+++ b/libgo/go/http/pprof/pprof.go
@@ -18,6 +18,10 @@
 //
 //	pprof http://localhost:6060/debug/pprof/heap
 //
+// Or to look at a 30-second CPU profile:
+//
+//	pprof http://localhost:6060/debug/pprof/profile
+//
 package pprof
 
 import (
@@ -29,10 +33,12 @@ import (
 	"runtime/pprof"
 	"strconv"
 	"strings"
+	"time"
 )
 
 func init() {
 	http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
+	http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
 	http.Handle("/debug/pprof/heap", http.HandlerFunc(Heap))
 	http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
 }
@@ -41,22 +47,46 @@ func init() {
 // command line, with arguments separated by NUL bytes.
 // The package initialization registers it as /debug/pprof/cmdline.
 func Cmdline(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("content-type", "text/plain; charset=utf-8")
+	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 	fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
 }
 
 // Heap responds with the pprof-formatted heap profile.
 // The package initialization registers it as /debug/pprof/heap.
 func Heap(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("content-type", "text/plain; charset=utf-8")
+	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 	pprof.WriteHeapProfile(w)
 }
 
+// Profile responds with the pprof-formatted cpu profile.
+// The package initialization registers it as /debug/pprof/profile.
+func Profile(w http.ResponseWriter, r *http.Request) {
+	sec, _ := strconv.Atoi64(r.FormValue("seconds"))
+	if sec == 0 {
+		sec = 30
+	}
+
+	// Set Content Type assuming StartCPUProfile will work,
+	// because if it does it starts writing.
+	w.Header().Set("Content-Type", "application/octet-stream")
+	if err := pprof.StartCPUProfile(w); err != nil {
+		// StartCPUProfile failed, so no writes yet.
+		// Can change header back to text content
+		// and send error code.
+		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+		w.WriteHeader(http.StatusInternalServerError)
+		fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
+		return
+	}
+	time.Sleep(sec * 1e9)
+	pprof.StopCPUProfile()
+}
+
 // Symbol looks up the program counters listed in the request,
 // responding with a table mapping program counters to function names.
 // The package initialization registers it as /debug/pprof/symbol.
 func Symbol(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("content-type", "text/plain; charset=utf-8")
+	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 
 	// We don't know how many symbols we have, but we
 	// do have symbol information.  Pprof only cares whether
diff --git a/libgo/go/http/serve_test.go b/libgo/go/http/serve_test.go
index 683de85b867..b0e26e53359 100644
--- a/libgo/go/http/serve_test.go
+++ b/libgo/go/http/serve_test.go
@@ -175,7 +175,7 @@ func TestHostHandlers(t *testing.T) {
 	ts := httptest.NewServer(nil)
 	defer ts.Close()
 
-	conn, err := net.Dial("tcp", "", ts.Listener.Addr().String())
+	conn, err := net.Dial("tcp", ts.Listener.Addr().String())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -265,7 +265,7 @@ func TestServerTimeouts(t *testing.T) {
 
 	// Slow client that should timeout.
 	t1 := time.Nanoseconds()
-	conn, err := net.Dial("tcp", "", fmt.Sprintf("localhost:%d", addr.Port))
+	conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", addr.Port))
 	if err != nil {
 		t.Fatalf("Dial: %v", err)
 	}
@@ -348,7 +348,7 @@ func TestIdentityResponse(t *testing.T) {
 	}
 	// Verify that the connection is closed when the declared Content-Length
 	// is larger than what the handler wrote.
-	conn, err := net.Dial("tcp", "", ts.Listener.Addr().String())
+	conn, err := net.Dial("tcp", ts.Listener.Addr().String())
 	if err != nil {
 		t.Fatalf("error dialing: %v", err)
 	}
@@ -377,7 +377,7 @@ func TestServeHTTP10Close(t *testing.T) {
 	}))
 	defer s.Close()
 
-	conn, err := net.Dial("tcp", "", s.Listener.Addr().String())
+	conn, err := net.Dial("tcp", s.Listener.Addr().String())
 	if err != nil {
 		t.Fatal("dial error:", err)
 	}
diff --git a/libgo/go/http/transport.go b/libgo/go/http/transport.go
index 8a73ead31f9..ed7843bc713 100644
--- a/libgo/go/http/transport.go
+++ b/libgo/go/http/transport.go
@@ -195,7 +195,7 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
 		return pc, nil
 	}
 
-	conn, err := net.Dial("tcp", "", cm.addr())
+	conn, err := net.Dial("tcp", cm.addr())
 	if err != nil {
 		return nil, err
 	}
diff --git a/libgo/go/image/png/reader_test.go b/libgo/go/image/png/reader_test.go
index 8314a833877..0b2058d51a2 100644
--- a/libgo/go/image/png/reader_test.go
+++ b/libgo/go/image/png/reader_test.go
@@ -34,6 +34,12 @@ var filenames = []string{
 	"basn6a16",
 }
 
+var filenamesShort = []string{
+	"basn0g01",
+	"basn0g04-31",
+	"basn6a16",
+}
+
 func readPng(filename string) (image.Image, os.Error) {
 	f, err := os.Open(filename, os.O_RDONLY, 0444)
 	if err != nil {
@@ -157,7 +163,11 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
 }
 
 func TestReader(t *testing.T) {
-	for _, fn := range filenames {
+	names := filenames
+	if testing.Short() {
+		names = filenamesShort
+	}
+	for _, fn := range names {
 		// Read the .png file.
 		img, err := readPng("testdata/pngsuite/" + fn + ".png")
 		if err != nil {
diff --git a/libgo/go/image/png/writer_test.go b/libgo/go/image/png/writer_test.go
index f218a5564bb..4d9929f314f 100644
--- a/libgo/go/image/png/writer_test.go
+++ b/libgo/go/image/png/writer_test.go
@@ -32,7 +32,11 @@ func diff(m0, m1 image.Image) os.Error {
 
 func TestWriter(t *testing.T) {
 	// The filenames variable is declared in reader_test.go.
-	for _, fn := range filenames {
+	names := filenames
+	if testing.Short() {
+		names = filenamesShort
+	}
+	for _, fn := range names {
 		qfn := "testdata/pngsuite/" + fn + ".png"
 		// Read the image.
 		m0, err := readPng(qfn)
diff --git a/libgo/go/json/decode_test.go b/libgo/go/json/decode_test.go
index ad6026363b5..aad8b635f2b 100644
--- a/libgo/go/json/decode_test.go
+++ b/libgo/go/json/decode_test.go
@@ -157,6 +157,7 @@ func TestUnmarshal(t *testing.T) {
 }
 
 func TestUnmarshalMarshal(t *testing.T) {
+	initBig()
 	var v interface{}
 	if err := Unmarshal(jsonBig, &v); err != nil {
 		t.Fatalf("Unmarshal: %v", err)
diff --git a/libgo/go/json/scanner_test.go b/libgo/go/json/scanner_test.go
index 2dc8ff87fb4..0d4de3246dd 100644
--- a/libgo/go/json/scanner_test.go
+++ b/libgo/go/json/scanner_test.go
@@ -85,6 +85,7 @@ func TestIndent(t *testing.T) {
 // Tests of a large random structure.
 
 func TestCompactBig(t *testing.T) {
+	initBig()
 	var buf bytes.Buffer
 	if err := Compact(&buf, jsonBig); err != nil {
 		t.Fatalf("Compact: %v", err)
@@ -98,6 +99,7 @@ func TestCompactBig(t *testing.T) {
 }
 
 func TestIndentBig(t *testing.T) {
+	initBig()
 	var buf bytes.Buffer
 	if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
 		t.Fatalf("Indent1: %v", err)
@@ -135,6 +137,7 @@ func TestIndentBig(t *testing.T) {
 }
 
 func TestNextValueBig(t *testing.T) {
+	initBig()
 	var scan scanner
 	item, rest, err := nextValue(jsonBig, &scan)
 	if err != nil {
@@ -160,6 +163,7 @@ func TestNextValueBig(t *testing.T) {
 }
 
 func BenchmarkSkipValue(b *testing.B) {
+	initBig()
 	var scan scanner
 	for i := 0; i < b.N; i++ {
 		nextValue(jsonBig, &scan)
@@ -191,12 +195,23 @@ func trim(b []byte) []byte {
 
 var jsonBig []byte
 
-func init() {
-	b, err := Marshal(genValue(10000))
-	if err != nil {
-		panic(err)
+const (
+	big   = 10000
+	small = 100
+)
+
+func initBig() {
+	n := big
+	if testing.Short() {
+		n = small
+	}
+	if len(jsonBig) != n {
+		b, err := Marshal(genValue(n))
+		if err != nil {
+			panic(err)
+		}
+		jsonBig = b
 	}
-	jsonBig = b
 }
 
 func genValue(n int) interface{} {
diff --git a/libgo/go/net/cgo_stub.go b/libgo/go/net/cgo_stub.go
new file mode 100644
index 00000000000..e28f6622e93
--- /dev/null
+++ b/libgo/go/net/cgo_stub.go
@@ -0,0 +1,21 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Stub cgo routines for systems that do not use cgo to do network lookups.
+
+package net
+
+import "os"
+
+func cgoLookupHost(name string) (addrs []string, err os.Error, completed bool) {
+	return nil, nil, false
+}
+
+func cgoLookupPort(network, service string) (port int, err os.Error, completed bool) {
+	return 0, nil, false
+}
+
+func cgoLookupIP(name string) (addrs []IP, err os.Error, completed bool) {
+	return nil, nil, false
+}
diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go
index 1cf8e79159e..66cb09b19bb 100644
--- a/libgo/go/net/dial.go
+++ b/libgo/go/net/dial.go
@@ -6,9 +6,7 @@ package net
 
 import "os"
 
-// Dial connects to the remote address raddr on the network net.
-// If the string laddr is not empty, it is used as the local address
-// for the connection.
+// Dial connects to the address addr on the network net.
 //
 // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
 // "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
@@ -16,79 +14,56 @@ import "os"
 //
 // For IP networks, addresses have the form host:port.  If host is
 // a literal IPv6 address, it must be enclosed in square brackets.
+// The functions JoinHostPort and SplitHostPort manipulate 
+// addresses in this form.
 //
 // Examples:
-//	Dial("tcp", "", "12.34.56.78:80")
-//	Dial("tcp", "", "google.com:80")
-//	Dial("tcp", "", "[de:ad:be:ef::ca:fe]:80")
-//	Dial("tcp", "127.0.0.1:123", "127.0.0.1:88")
+//	Dial("tcp", "12.34.56.78:80")
+//	Dial("tcp", "google.com:80")
+//	Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
 //
-func Dial(net, laddr, raddr string) (c Conn, err os.Error) {
+func Dial(net, addr string) (c Conn, err os.Error) {
+	raddr := addr
+	if raddr == "" {
+		return nil, &OpError{"dial", net, nil, errMissingAddress}
+	}
 	switch net {
 	case "tcp", "tcp4", "tcp6":
-		var la, ra *TCPAddr
-		if laddr != "" {
-			if la, err = ResolveTCPAddr(laddr); err != nil {
-				goto Error
-			}
-		}
-		if raddr != "" {
-			if ra, err = ResolveTCPAddr(raddr); err != nil {
-				goto Error
-			}
+		var ra *TCPAddr
+		if ra, err = ResolveTCPAddr(raddr); err != nil {
+			goto Error
 		}
-		c, err := DialTCP(net, la, ra)
+		c, err := DialTCP(net, nil, ra)
 		if err != nil {
 			return nil, err
 		}
 		return c, nil
 	case "udp", "udp4", "udp6":
-		var la, ra *UDPAddr
-		if laddr != "" {
-			if la, err = ResolveUDPAddr(laddr); err != nil {
-				goto Error
-			}
-		}
-		if raddr != "" {
-			if ra, err = ResolveUDPAddr(raddr); err != nil {
-				goto Error
-			}
+		var ra *UDPAddr
+		if ra, err = ResolveUDPAddr(raddr); err != nil {
+			goto Error
 		}
-		c, err := DialUDP(net, la, ra)
+		c, err := DialUDP(net, nil, ra)
 		if err != nil {
 			return nil, err
 		}
 		return c, nil
 	case "unix", "unixgram", "unixpacket":
-		var la, ra *UnixAddr
-		if raddr != "" {
-			if ra, err = ResolveUnixAddr(net, raddr); err != nil {
-				goto Error
-			}
-		}
-		if laddr != "" {
-			if la, err = ResolveUnixAddr(net, laddr); err != nil {
-				goto Error
-			}
+		var ra *UnixAddr
+		if ra, err = ResolveUnixAddr(net, raddr); err != nil {
+			goto Error
 		}
-		c, err = DialUnix(net, la, ra)
+		c, err = DialUnix(net, nil, ra)
 		if err != nil {
 			return nil, err
 		}
 		return c, nil
 	case "ip", "ip4", "ip6":
-		var la, ra *IPAddr
-		if laddr != "" {
-			if la, err = ResolveIPAddr(laddr); err != nil {
-				goto Error
-			}
-		}
-		if raddr != "" {
-			if ra, err = ResolveIPAddr(raddr); err != nil {
-				goto Error
-			}
+		var ra *IPAddr
+		if ra, err = ResolveIPAddr(raddr); err != nil {
+			goto Error
 		}
-		c, err := DialIP(net, la, ra)
+		c, err := DialIP(net, nil, ra)
 		if err != nil {
 			return nil, err
 		}
diff --git a/libgo/go/net/dialgoogle_test.go b/libgo/go/net/dialgoogle_test.go
index a432800cfe2..9a9c02ebd71 100644
--- a/libgo/go/net/dialgoogle_test.go
+++ b/libgo/go/net/dialgoogle_test.go
@@ -32,7 +32,7 @@ func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
 }
 
 func doDial(t *testing.T, network, addr string) {
-	fd, err := Dial(network, "", addr)
+	fd, err := Dial(network, addr)
 	if err != nil {
 		t.Errorf("Dial(%q, %q, %q) = _, %v", network, "", addr, err)
 		return
@@ -55,6 +55,13 @@ var googleaddrs = []string{
 	"[2001:4860:0:2001::68]:80", // ipv6.google.com; removed if ipv6 flag not set
 }
 
+func TestLookupCNAME(t *testing.T) {
+	cname, err := LookupCNAME("www.google.com")
+	if cname != "www.l.google.com." || err != nil {
+		t.Errorf(`LookupCNAME("www.google.com.") = %q, %v, want "www.l.google.com.", nil`, cname, err)
+	}
+}
+
 func TestDialGoogle(t *testing.T) {
 	// If no ipv6 tunnel, don't try the last address.
 	if !*ipv6 {
@@ -64,14 +71,14 @@ func TestDialGoogle(t *testing.T) {
 	// Insert an actual IP address for google.com
 	// into the table.
 
-	_, addrs, err := LookupHost("www.google.com")
+	addrs, err := LookupIP("www.google.com")
 	if err != nil {
 		t.Fatalf("lookup www.google.com: %v", err)
 	}
 	if len(addrs) == 0 {
 		t.Fatalf("no addresses for www.google.com")
 	}
-	ip := ParseIP(addrs[0]).To4()
+	ip := addrs[0].To4()
 
 	for i, s := range googleaddrs {
 		if strings.Contains(s, "%") {
diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go
index 3252dd45406..32cea6125eb 100644
--- a/libgo/go/net/dnsclient.go
+++ b/libgo/go/net/dnsclient.go
@@ -159,7 +159,7 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs
 		// all the cfg.servers[i] are IP addresses, which
 		// Dial will use without a DNS lookup.
 		server := cfg.servers[i] + ":53"
-		c, cerr := Dial("udp", "", server)
+		c, cerr := Dial("udp", server)
 		if cerr != nil {
 			err = cerr
 			continue
@@ -178,12 +178,23 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs
 	return
 }
 
-func convertRR_A(records []dnsRR) []string {
-	addrs := make([]string, len(records))
+func convertRR_A(records []dnsRR) []IP {
+	addrs := make([]IP, len(records))
 	for i := 0; i < len(records); i++ {
 		rr := records[i]
 		a := rr.(*dnsRR_A).A
-		addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a)).String()
+		addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
+	}
+	return addrs
+}
+
+func convertRR_AAAA(records []dnsRR) []IP {
+	addrs := make([]IP, len(records))
+	for i := 0; i < len(records); i++ {
+		rr := records[i]
+		a := make(IP, 16)
+		copy(a, rr.(*dnsRR_AAAA).AAAA[:])
+		addrs[i] = a
 	}
 	return addrs
 }
@@ -294,10 +305,8 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro
 	return
 }
 
-// LookupHost looks for name using the local hosts file and DNS resolver.
-// It returns the canonical name for the host and an array of that
-// host's addresses.
-func LookupHost(name string) (cname string, addrs []string, err os.Error) {
+// goLookupHost is the native Go implementation of LookupHost.
+func goLookupHost(name string) (addrs []string, err os.Error) {
 	onceLoadConfig.Do(loadConfig)
 	if dnserr != nil || cfg == nil {
 		err = dnserr
@@ -306,18 +315,69 @@ func LookupHost(name string) (cname string, addrs []string, err os.Error) {
 	// Use entries from /etc/hosts if they match.
 	addrs = lookupStaticHost(name)
 	if len(addrs) > 0 {
-		cname = name
+		return
+	}
+	ips, err := goLookupIP(name)
+	if err != nil {
+		return
+	}
+	addrs = make([]string, 0, len(ips))
+	for _, ip := range ips {
+		addrs = append(addrs, ip.String())
+	}
+	return
+}
+
+// goLookupIP is the native Go implementation of LookupIP.
+func goLookupIP(name string) (addrs []IP, err os.Error) {
+	onceLoadConfig.Do(loadConfig)
+	if dnserr != nil || cfg == nil {
+		err = dnserr
 		return
 	}
 	var records []dnsRR
+	var cname string
 	cname, records, err = lookup(name, dnsTypeA)
 	if err != nil {
 		return
 	}
 	addrs = convertRR_A(records)
+	if cname != "" {
+		name = cname
+	}
+	_, records, err = lookup(name, dnsTypeAAAA)
+	if err != nil && len(addrs) > 0 {
+		// Ignore error because A lookup succeeded.
+		err = nil
+	}
+	if err != nil {
+		return
+	}
+	addrs = append(addrs, convertRR_AAAA(records)...)
+	return
+}
+
+// LookupCNAME returns the canonical DNS host for the given name.
+// Callers that do not care about the canonical name can call
+// LookupHost or LookupIP directly; both take care of resolving
+// the canonical name as part of the lookup.
+func LookupCNAME(name string) (cname string, err os.Error) {
+	onceLoadConfig.Do(loadConfig)
+	if dnserr != nil || cfg == nil {
+		err = dnserr
+		return
+	}
+	_, rr, err := lookup(name, dnsTypeCNAME)
+	if err != nil {
+		return
+	}
+	if len(rr) >= 0 {
+		cname = rr[0].(*dnsRR_CNAME).Cname
+	}
 	return
 }
 
+// An SRV represents a single DNS SRV record.
 type SRV struct {
 	Target   string
 	Port     uint16
@@ -344,11 +404,13 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
 	return
 }
 
+// An MX represents a single DNS MX record.
 type MX struct {
 	Host string
 	Pref uint16
 }
 
+// LookupMX returns the DNS MX records associated with name.
 func LookupMX(name string) (entries []*MX, err os.Error) {
 	var records []dnsRR
 	_, records, err = lookup(name, dnsTypeMX)
diff --git a/libgo/go/net/dnsmsg.go b/libgo/go/net/dnsmsg.go
index dc195caf801..5209c1a06a5 100644
--- a/libgo/go/net/dnsmsg.go
+++ b/libgo/go/net/dnsmsg.go
@@ -50,6 +50,7 @@ const (
 	dnsTypeMINFO = 14
 	dnsTypeMX    = 15
 	dnsTypeTXT   = 16
+	dnsTypeAAAA  = 28
 	dnsTypeSRV   = 33
 
 	// valid dnsQuestion.qtype only
@@ -244,8 +245,18 @@ type dnsRR_A struct {
 	A   uint32 "ipv4"
 }
 
-func (rr *dnsRR_A) Header() *dnsRR_Header { return &rr.Hdr }
+func (rr *dnsRR_A) Header() *dnsRR_Header {
+	return &rr.Hdr
+}
+
+type dnsRR_AAAA struct {
+	Hdr  dnsRR_Header
+	AAAA [16]byte "ipv6"
+}
 
+func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
+	return &rr.Hdr
+}
 
 // Packing and unpacking.
 //
@@ -270,6 +281,7 @@ var rr_mk = map[int]func() dnsRR{
 	dnsTypeTXT:   func() dnsRR { return new(dnsRR_TXT) },
 	dnsTypeSRV:   func() dnsRR { return new(dnsRR_SRV) },
 	dnsTypeA:     func() dnsRR { return new(dnsRR_A) },
+	dnsTypeAAAA:  func() dnsRR { return new(dnsRR_AAAA) },
 }
 
 // Pack a domain name s into msg[off:].
@@ -377,7 +389,7 @@ Loop:
 
 // TODO(rsc): Move into generic library?
 // Pack a reflect.StructValue into msg.  Struct members can only be uint16, uint32, string,
-// and other (often anonymous) structs.
+// [n]byte, and other (often anonymous) structs.
 func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, ok bool) {
 	for i := 0; i < val.NumField(); i++ {
 		f := val.Type().(*reflect.StructType).Field(i)
@@ -410,6 +422,16 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o
 				msg[off+3] = byte(i)
 				off += 4
 			}
+		case *reflect.ArrayValue:
+			if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 {
+				goto BadType
+			}
+			n := fv.Len()
+			if off+n > len(msg) {
+				return len(msg), false
+			}
+			reflect.Copy(reflect.NewValue(msg[off:off+n]).(*reflect.SliceValue), fv)
+			off += n
 		case *reflect.StringValue:
 			// There are multiple string encodings.
 			// The tag distinguishes ordinary strings from domain names.
@@ -478,6 +500,16 @@ func unpackStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int,
 				fv.Set(uint64(i))
 				off += 4
 			}
+		case *reflect.ArrayValue:
+			if fv.Type().(*reflect.ArrayType).Elem().Kind() != reflect.Uint8 {
+				goto BadType
+			}
+			n := fv.Len()
+			if off+n > len(msg) {
+				return len(msg), false
+			}
+			reflect.Copy(fv, reflect.NewValue(msg[off:off+n]).(*reflect.SliceValue))
+			off += n
 		case *reflect.StringValue:
 			var s string
 			switch f.Tag {
@@ -515,7 +547,8 @@ func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
 
 // Generic struct printer.
 // Doesn't care about the string tag "domain-name",
-// but does look for an "ipv4" tag on uint32 variables,
+// but does look for an "ipv4" tag on uint32 variables
+// and the "ipv6" tag on array variables,
 // printing them as IP addresses.
 func printStructValue(val *reflect.StructValue) string {
 	s := "{"
@@ -533,6 +566,9 @@ func printStructValue(val *reflect.StructValue) string {
 		} else if fv, ok := fval.(*reflect.UintValue); ok && f.Tag == "ipv4" {
 			i := fv.Get()
 			s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
+		} else if fv, ok := fval.(*reflect.ArrayValue); ok && f.Tag == "ipv6" {
+			i := fv.Interface().([]byte)
+			s += IP(i).String()
 		} else {
 			s += fmt.Sprint(fval.Interface())
 		}
diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go
index c8440ae484a..7e4b83a9f99 100644
--- a/libgo/go/net/fd.go
+++ b/libgo/go/net/fd.go
@@ -274,19 +274,25 @@ func startServer() {
 	pollserver = p
 }
 
-func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
+func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) {
 	onceStartServer.Do(startServer)
 	if e := syscall.SetNonblock(fd, true); e != 0 {
-		return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)}
+		return nil, os.Errno(e)
 	}
 	f = &netFD{
 		sysfd:  fd,
 		family: family,
 		proto:  proto,
 		net:    net,
-		laddr:  laddr,
-		raddr:  raddr,
 	}
+	f.cr = make(chan bool, 1)
+	f.cw = make(chan bool, 1)
+	return f, nil
+}
+
+func (fd *netFD) setAddr(laddr, raddr Addr) {
+	fd.laddr = laddr
+	fd.raddr = raddr
 	var ls, rs string
 	if laddr != nil {
 		ls = laddr.String()
@@ -294,10 +300,23 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err
 	if raddr != nil {
 		rs = raddr.String()
 	}
-	f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs)
-	f.cr = make(chan bool, 1)
-	f.cw = make(chan bool, 1)
-	return f, nil
+	fd.sysfile = os.NewFile(fd.sysfd, fd.net+":"+ls+"->"+rs)
+}
+
+func (fd *netFD) connect(ra syscall.Sockaddr) (err os.Error) {
+	e := syscall.Connect(fd.sysfd, ra)
+	if e == syscall.EINPROGRESS {
+		var errno int
+		pollserver.WaitWrite(fd)
+		e, errno = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+		if errno != 0 {
+			return os.NewSyscallError("getsockopt", errno)
+		}
+	}
+	if e != 0 {
+		return os.Errno(e)
+	}
+	return nil
 }
 
 // Add a reference to this fd.
@@ -593,10 +612,11 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
 	syscall.CloseOnExec(s)
 	syscall.ForkLock.RUnlock()
 
-	if nfd, err = newFD(s, fd.family, fd.proto, fd.net, fd.laddr, toAddr(sa)); err != nil {
+	if nfd, err = newFD(s, fd.family, fd.proto, fd.net); err != nil {
 		syscall.Close(s)
 		return nil, err
 	}
+	nfd.setAddr(fd.laddr, toAddr(sa))
 	return nfd, nil
 }
 
diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go
index 63a8fbc4489..c2f736cc126 100644
--- a/libgo/go/net/fd_windows.go
+++ b/libgo/go/net/fd_windows.go
@@ -225,29 +225,40 @@ type netFD struct {
 	wio             sync.Mutex
 }
 
-func allocFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD) {
+func allocFD(fd, family, proto int, net string) (f *netFD) {
 	f = &netFD{
 		sysfd:  fd,
 		family: family,
 		proto:  proto,
 		net:    net,
-		laddr:  laddr,
-		raddr:  raddr,
 	}
 	runtime.SetFinalizer(f, (*netFD).Close)
 	return f
 }
 
-func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
+func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) {
 	if initErr != nil {
 		return nil, initErr
 	}
 	onceStartServer.Do(startServer)
 	// Associate our socket with resultsrv.iocp.
 	if _, e := syscall.CreateIoCompletionPort(int32(fd), resultsrv.iocp, 0, 0); e != 0 {
-		return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)}
+		return nil, os.Errno(e)
+	}
+	return allocFD(fd, family, proto, net), nil
+}
+
+func (fd *netFD) setAddr(laddr, raddr Addr) {
+	fd.laddr = laddr
+	fd.raddr = raddr
+}
+
+func (fd *netFD) connect(ra syscall.Sockaddr) (err os.Error) {
+	e := syscall.Connect(fd.sysfd, ra)
+	if e != 0 {
+		return os.Errno(e)
 	}
-	return allocFD(fd, family, proto, net, laddr, raddr), nil
+	return nil
 }
 
 // Add a reference to this fd.
@@ -497,7 +508,9 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
 	lsa, _ := lrsa.Sockaddr()
 	rsa, _ := rrsa.Sockaddr()
 
-	return allocFD(s, fd.family, fd.proto, fd.net, toAddr(lsa), toAddr(rsa)), nil
+	nfd = allocFD(s, fd.family, fd.proto, fd.net)
+	nfd.setAddr(toAddr(lsa), toAddr(rsa))
+	return nfd, nil
 }
 
 // Not implemeted functions.
diff --git a/libgo/go/net/file.go b/libgo/go/net/file.go
new file mode 100644
index 00000000000..0e411a192f2
--- /dev/null
+++ b/libgo/go/net/file.go
@@ -0,0 +1,119 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+	"os"
+	"syscall"
+)
+
+func newFileFD(f *os.File) (nfd *netFD, err os.Error) {
+	fd, errno := syscall.Dup(f.Fd())
+	if errno != 0 {
+		return nil, os.NewSyscallError("dup", errno)
+	}
+
+	proto, errno := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
+	if errno != 0 {
+		return nil, os.NewSyscallError("getsockopt", errno)
+	}
+
+	toAddr := sockaddrToTCP
+	sa, _ := syscall.Getsockname(fd)
+	switch sa.(type) {
+	default:
+		closesocket(fd)
+		return nil, os.EINVAL
+	case *syscall.SockaddrInet4:
+		if proto == syscall.SOCK_DGRAM {
+			toAddr = sockaddrToUDP
+		} else if proto == syscall.SOCK_RAW {
+			toAddr = sockaddrToIP
+		}
+	case *syscall.SockaddrInet6:
+		if proto == syscall.SOCK_DGRAM {
+			toAddr = sockaddrToUDP
+		} else if proto == syscall.SOCK_RAW {
+			toAddr = sockaddrToIP
+		}
+	case *syscall.SockaddrUnix:
+		toAddr = sockaddrToUnix
+		if proto == syscall.SOCK_DGRAM {
+			toAddr = sockaddrToUnixgram
+		} else if proto == syscall.SOCK_SEQPACKET {
+			toAddr = sockaddrToUnixpacket
+		}
+	}
+	laddr := toAddr(sa)
+	sa, _ = syscall.Getpeername(fd)
+	raddr := toAddr(sa)
+
+	if nfd, err = newFD(fd, 0, proto, laddr.Network()); err != nil {
+		return nil, err
+	}
+	nfd.setAddr(laddr, raddr)
+	return nfd, nil
+}
+
+// FileConn returns a copy of the network connection corresponding to
+// the open file f.  It is the caller's responsibility to close f when
+// finished.  Closing c does not affect f, and closing f does not
+// affect c.
+func FileConn(f *os.File) (c Conn, err os.Error) {
+	fd, err := newFileFD(f)
+	if err != nil {
+		return nil, err
+	}
+	switch fd.laddr.(type) {
+	case *TCPAddr:
+		return newTCPConn(fd), nil
+	case *UDPAddr:
+		return newUDPConn(fd), nil
+	case *UnixAddr:
+		return newUnixConn(fd), nil
+	case *IPAddr:
+		return newIPConn(fd), nil
+	}
+	fd.Close()
+	return nil, os.EINVAL
+}
+
+// FileListener returns a copy of the network listener corresponding
+// to the open file f.  It is the caller's responsibility to close l
+// when finished.  Closing c does not affect l, and closing l does not
+// affect c.
+func FileListener(f *os.File) (l Listener, err os.Error) {
+	fd, err := newFileFD(f)
+	if err != nil {
+		return nil, err
+	}
+	switch laddr := fd.laddr.(type) {
+	case *TCPAddr:
+		return &TCPListener{fd}, nil
+	case *UnixAddr:
+		return &UnixListener{fd, laddr.Name}, nil
+	}
+	fd.Close()
+	return nil, os.EINVAL
+}
+
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f.  It is the caller's
+// responsibility to close f when finished.  Closing c does not affect
+// f, and closing f does not affect c.
+func FilePacketConn(f *os.File) (c PacketConn, err os.Error) {
+	fd, err := newFileFD(f)
+	if err != nil {
+		return nil, err
+	}
+	switch fd.laddr.(type) {
+	case *UDPAddr:
+		return newUDPConn(fd), nil
+	case *UnixAddr:
+		return newUnixConn(fd), nil
+	}
+	fd.Close()
+	return nil, os.EINVAL
+}
diff --git a/libgo/go/net/file_test.go b/libgo/go/net/file_test.go
new file mode 100644
index 00000000000..1ec05fdeea5
--- /dev/null
+++ b/libgo/go/net/file_test.go
@@ -0,0 +1,131 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+	"os"
+	"reflect"
+	"runtime"
+	"syscall"
+	"testing"
+)
+
+type listenerFile interface {
+	Listener
+	File() (f *os.File, err os.Error)
+}
+
+type packetConnFile interface {
+	PacketConn
+	File() (f *os.File, err os.Error)
+}
+
+type connFile interface {
+	Conn
+	File() (f *os.File, err os.Error)
+}
+
+func testFileListener(t *testing.T, net, laddr string) {
+	if net == "tcp" {
+		laddr += ":0" // any available port
+	}
+	l, err := Listen(net, laddr)
+	if err != nil {
+		t.Fatalf("Listen failed: %v", err)
+	}
+	defer l.Close()
+	lf := l.(listenerFile)
+	f, err := lf.File()
+	if err != nil {
+		t.Fatalf("File failed: %v", err)
+	}
+	c, err := FileListener(f)
+	if err != nil {
+		t.Fatalf("FileListener failed: %v", err)
+	}
+	if !reflect.DeepEqual(l.Addr(), c.Addr()) {
+		t.Fatalf("Addrs not equal: %#v != %#v", l.Addr(), c.Addr())
+	}
+	if err := c.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+	if err := f.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+}
+
+func TestFileListener(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		return
+	}
+	testFileListener(t, "tcp", "127.0.0.1")
+	testFileListener(t, "tcp", "127.0.0.1")
+	if kernelSupportsIPv6() {
+		testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
+		testFileListener(t, "tcp", "127.0.0.1")
+		testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
+	}
+	if syscall.OS == "linux" {
+		testFileListener(t, "unix", "@gotest/net")
+		testFileListener(t, "unixpacket", "@gotest/net")
+	}
+}
+
+func testFilePacketConn(t *testing.T, pcf packetConnFile) {
+	f, err := pcf.File()
+	if err != nil {
+		t.Fatalf("File failed: %v", err)
+	}
+	c, err := FilePacketConn(f)
+	if err != nil {
+		t.Fatalf("FilePacketConn failed: %v", err)
+	}
+	if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) {
+		t.Fatalf("LocalAddrs not equal: %#v != %#v", pcf.LocalAddr(), c.LocalAddr())
+	}
+	if err := c.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+	if err := f.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+}
+
+func testFilePacketConnListen(t *testing.T, net, laddr string) {
+	l, err := ListenPacket(net, laddr)
+	if err != nil {
+		t.Fatalf("Listen failed: %v", err)
+	}
+	testFilePacketConn(t, l.(packetConnFile))
+	if err := l.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+}
+
+func testFilePacketConnDial(t *testing.T, net, raddr string) {
+	c, err := Dial(net, raddr)
+	if err != nil {
+		t.Fatalf("Dial failed: %v", err)
+	}
+	testFilePacketConn(t, c.(packetConnFile))
+	if err := c.Close(); err != nil {
+		t.Fatalf("Close failed: %v", err)
+	}
+}
+
+func TestFilePacketConn(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		return
+	}
+	testFilePacketConnListen(t, "udp", "127.0.0.1:0")
+	testFilePacketConnDial(t, "udp", "127.0.0.1:12345")
+	if kernelSupportsIPv6() {
+		testFilePacketConnListen(t, "udp", "[::1]:0")
+		testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345")
+	}
+	if syscall.OS == "linux" {
+		testFilePacketConnListen(t, "unixgram", "@gotest1/net")
+	}
+}
diff --git a/libgo/go/net/file_windows.go b/libgo/go/net/file_windows.go
new file mode 100644
index 00000000000..94aa583755b
--- /dev/null
+++ b/libgo/go/net/file_windows.go
@@ -0,0 +1,25 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+	"os"
+	"syscall"
+)
+
+func FileConn(f *os.File) (c Conn, err os.Error) {
+	// TODO: Implement this
+	return nil, os.NewSyscallError("FileConn", syscall.EWINDOWS)
+}
+
+func FileListener(f *os.File) (l Listener, err os.Error) {
+	// TODO: Implement this
+	return nil, os.NewSyscallError("FileListener", syscall.EWINDOWS)
+}
+
+func FilePacketConn(f *os.File) (c PacketConn, err os.Error) {
+	// TODO: Implement this
+	return nil, os.NewSyscallError("FilePacketConn", syscall.EWINDOWS)
+}
diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go
index 84cd92e376c..470e35f7863 100644
--- a/libgo/go/net/hosts_test.go
+++ b/libgo/go/net/hosts_test.go
@@ -13,7 +13,6 @@ type hostTest struct {
 	ips  []IP
 }
 
-
 var hosttests = []hostTest{
 	{"odin", []IP{
 		IPv4(127, 0, 0, 2),
diff --git a/libgo/go/net/ip.go b/libgo/go/net/ip.go
index 1904af0d6ad..12bb6f351a1 100644
--- a/libgo/go/net/ip.go
+++ b/libgo/go/net/ip.go
@@ -474,13 +474,13 @@ func parseIPv6(s string) IP {
 	return p
 }
 
-// A SyntaxError represents a malformed text string and the type of string that was expected.
-type SyntaxError struct {
+// A ParseError represents a malformed text string and the type of string that was expected.
+type ParseError struct {
 	Type string
 	Text string
 }
 
-func (e *SyntaxError) String() string {
+func (e *ParseError) String() string {
 	return "invalid " + e.Type + ": " + e.Text
 }
 
@@ -507,33 +507,46 @@ func ParseIP(s string) IP {
 }
 
 // ParseCIDR parses s as a CIDR notation IP address and mask,
-// like "192.168.100.1/24" or "2001:DB8::/48".
+// like "192.168.100.1/24", "2001:DB8::/48", as defined in
+// RFC 4632 and RFC 4291.
 func ParseCIDR(s string) (ip IP, mask IPMask, err os.Error) {
 	i := byteIndex(s, '/')
 	if i < 0 {
-		return nil, nil, &SyntaxError{"CIDR address", s}
+		return nil, nil, &ParseError{"CIDR address", s}
 	}
 	ipstr, maskstr := s[:i], s[i+1:]
-	ip = ParseIP(ipstr)
+	iplen := 4
+	ip = parseIPv4(ipstr)
+	if ip == nil {
+		iplen = 16
+		ip = parseIPv6(ipstr)
+	}
 	nn, i, ok := dtoi(maskstr, 0)
-	if ip == nil || !ok || i != len(maskstr) || nn < 0 || nn > 8*len(ip) {
-		return nil, nil, &SyntaxError{"CIDR address", s}
+	if ip == nil || !ok || i != len(maskstr) || nn < 0 || nn > 8*iplen {
+		return nil, nil, &ParseError{"CIDR address", s}
 	}
 	n := uint(nn)
-	if len(ip) == 4 {
+	if iplen == 4 {
 		v4mask := ^uint32(0xffffffff >> n)
-		mask = IPMask(IPv4(byte(v4mask>>24), byte(v4mask>>16), byte(v4mask>>8), byte(v4mask)))
-		return ip, mask, nil
-	}
-	mask = make(IPMask, 16)
-	for i := 0; i < 16; i++ {
-		if n >= 8 {
-			mask[i] = 0xff
-			n -= 8
-			continue
+		mask = IPv4Mask(byte(v4mask>>24), byte(v4mask>>16), byte(v4mask>>8), byte(v4mask))
+	} else {
+		mask = make(IPMask, 16)
+		for i := 0; i < 16; i++ {
+			if n >= 8 {
+				mask[i] = 0xff
+				n -= 8
+				continue
+			}
+			mask[i] = ^byte(0xff >> n)
+			n = 0
+
+		}
+	}
+	// address must not have any bits not in mask
+	for i := range ip {
+		if ip[i]&^mask[i] != 0 {
+			return nil, nil, &ParseError{"CIDR address", s}
 		}
-		mask[i] = ^byte(0xff >> n)
-		n = 0
 	}
 	return ip, mask, nil
 }
diff --git a/libgo/go/net/ip_test.go b/libgo/go/net/ip_test.go
index e29c3021da9..f1a4716d227 100644
--- a/libgo/go/net/ip_test.go
+++ b/libgo/go/net/ip_test.go
@@ -5,30 +5,26 @@
 package net
 
 import (
+	"bytes"
+	"reflect"
 	"testing"
+	"os"
 )
 
-func isEqual(a, b IP) bool {
+func isEqual(a, b []byte) bool {
 	if a == nil && b == nil {
 		return true
 	}
-	if a == nil || b == nil || len(a) != len(b) {
+	if a == nil || b == nil {
 		return false
 	}
-	for i := 0; i < len(a); i++ {
-		if a[i] != b[i] {
-			return false
-		}
-	}
-	return true
+	return bytes.Equal(a, b)
 }
 
-type parseIPTest struct {
+var parseiptests = []struct {
 	in  string
 	out IP
-}
-
-var parseiptests = []parseIPTest{
+}{
 	{"127.0.1.2", IPv4(127, 0, 1, 2)},
 	{"127.0.0.1", IPv4(127, 0, 0, 1)},
 	{"127.0.0.256", nil},
@@ -43,20 +39,17 @@ var parseiptests = []parseIPTest{
 }
 
 func TestParseIP(t *testing.T) {
-	for i := 0; i < len(parseiptests); i++ {
-		tt := parseiptests[i]
+	for _, tt := range parseiptests {
 		if out := ParseIP(tt.in); !isEqual(out, tt.out) {
 			t.Errorf("ParseIP(%#q) = %v, want %v", tt.in, out, tt.out)
 		}
 	}
 }
 
-type ipStringTest struct {
+var ipstringtests = []struct {
 	in  IP
 	out string
-}
-
-var ipstringtests = []ipStringTest{
+}{
 	// cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation)
 	{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
 		0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
@@ -85,10 +78,67 @@ var ipstringtests = []ipStringTest{
 }
 
 func TestIPString(t *testing.T) {
-	for i := 0; i < len(ipstringtests); i++ {
-		tt := ipstringtests[i]
+	for _, tt := range ipstringtests {
 		if out := tt.in.String(); out != tt.out {
 			t.Errorf("IP.String(%v) = %#q, want %#q", tt.in, out, tt.out)
 		}
 	}
 }
+
+var parsecidrtests = []struct {
+	in   string
+	ip   IP
+	mask IPMask
+	err  os.Error
+}{
+	{"135.104.0.0/32", IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 255), nil},
+	{"0.0.0.0/24", IPv4(0, 0, 0, 0), IPv4Mask(255, 255, 255, 0), nil},
+	{"135.104.0.0/24", IPv4(135, 104, 0, 0), IPv4Mask(255, 255, 255, 0), nil},
+	{"135.104.0.1/32", IPv4(135, 104, 0, 1), IPv4Mask(255, 255, 255, 255), nil},
+	{"135.104.0.1/24", nil, nil, &ParseError{"CIDR address", "135.104.0.1/24"}},
+	{"::1/128", ParseIP("::1"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")), nil},
+	{"abcd:2345::/127", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe")), nil},
+	{"abcd:2345::/65", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff:8000::")), nil},
+	{"abcd:2345::/64", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:ffff::")), nil},
+	{"abcd:2345::/63", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:ffff:fffe::")), nil},
+	{"abcd:2345::/33", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff:8000::")), nil},
+	{"abcd:2345::/32", ParseIP("abcd:2345::"), IPMask(ParseIP("ffff:ffff::")), nil},
+	{"abcd:2344::/31", ParseIP("abcd:2344::"), IPMask(ParseIP("ffff:fffe::")), nil},
+	{"abcd:2300::/24", ParseIP("abcd:2300::"), IPMask(ParseIP("ffff:ff00::")), nil},
+	{"abcd:2345::/24", nil, nil, &ParseError{"CIDR address", "abcd:2345::/24"}},
+	{"2001:DB8::/48", ParseIP("2001:DB8::"), IPMask(ParseIP("ffff:ffff:ffff::")), nil},
+}
+
+func TestParseCIDR(t *testing.T) {
+	for _, tt := range parsecidrtests {
+		if ip, mask, err := ParseCIDR(tt.in); !isEqual(ip, tt.ip) || !isEqual(mask, tt.mask) || !reflect.DeepEqual(err, tt.err) {
+			t.Errorf("ParseCIDR(%q) = %v, %v, %v; want %v, %v, %v", tt.in, ip, mask, err, tt.ip, tt.mask, tt.err)
+		}
+	}
+}
+
+var splitjointests = []struct {
+	Host string
+	Port string
+	Join string
+}{
+	{"www.google.com", "80", "www.google.com:80"},
+	{"127.0.0.1", "1234", "127.0.0.1:1234"},
+	{"::1", "80", "[::1]:80"},
+}
+
+func TestSplitHostPort(t *testing.T) {
+	for _, tt := range splitjointests {
+		if host, port, err := SplitHostPort(tt.Join); host != tt.Host || port != tt.Port || err != nil {
+			t.Errorf("SplitHostPort(%q) = %q, %q, %v; want %q, %q, nil", tt.Join, host, port, err, tt.Host, tt.Port)
+		}
+	}
+}
+
+func TestJoinHostPort(t *testing.T) {
+	for _, tt := range splitjointests {
+		if join := JoinHostPort(tt.Host, tt.Port); join != tt.Join {
+			t.Errorf("JoinHostPort(%q, %q) = %q; want %q", tt.Host, tt.Port, join, tt.Join)
+		}
+	}
+}
diff --git a/libgo/go/net/iprawsock.go b/libgo/go/net/iprawsock.go
index 81a918ce5cb..60433303ae1 100644
--- a/libgo/go/net/iprawsock.go
+++ b/libgo/go/net/iprawsock.go
@@ -240,7 +240,7 @@ func hostToIP(host string) (ip IP, err os.Error) {
 	addr = ParseIP(host)
 	if addr == nil {
 		// Not an IP address.  Try as a DNS name.
-		_, addrs, err1 := LookupHost(host)
+		addrs, err1 := LookupHost(host)
 		if err1 != nil {
 			err = err1
 			goto Error
diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go
index ae4204b48aa..80bc3eea5da 100644
--- a/libgo/go/net/ipsock.go
+++ b/libgo/go/net/ipsock.go
@@ -170,9 +170,10 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
 	return nil, InvalidAddrError("unexpected socket family")
 }
 
-// Split "host:port" into "host" and "port".
-// Host cannot contain colons unless it is bracketed.
-func splitHostPort(hostport string) (host, port string, err os.Error) {
+// SplitHostPort splits a network address of the form
+// "host:port" or "[host]:port" into host and port.
+// The latter form must be used when host contains a colon.
+func SplitHostPort(hostport string) (host, port string, err os.Error) {
 	// The port starts after the last colon.
 	i := last(hostport, ':')
 	if i < 0 {
@@ -195,9 +196,9 @@ func splitHostPort(hostport string) (host, port string, err os.Error) {
 	return
 }
 
-// Join "host" and "port" into "host:port".
-// If host contains colons, will join into "[host]:port".
-func joinHostPort(host, port string) string {
+// JoinHostPort combines host and port into a network address
+// of the form "host:port" or, if host contains a colon, "[host]:port".
+func JoinHostPort(host, port string) string {
 	// If host has colons, have to bracket it.
 	if byteIndex(host, ':') >= 0 {
 		return "[" + host + "]:" + port
@@ -207,7 +208,7 @@ func joinHostPort(host, port string) string {
 
 // Convert "host:port" into IP address and port.
 func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
-	host, port, err := splitHostPort(hostport)
+	host, port, err := SplitHostPort(hostport)
 	if err != nil {
 		goto Error
 	}
@@ -218,7 +219,7 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
 		addr = ParseIP(host)
 		if addr == nil {
 			// Not an IP address.  Try as a DNS name.
-			_, addrs, err1 := LookupHost(host)
+			addrs, err1 := LookupHost(host)
 			if err1 != nil {
 				err = err1
 				goto Error
diff --git a/libgo/go/net/lookup.go b/libgo/go/net/lookup.go
new file mode 100644
index 00000000000..7b2185ed419
--- /dev/null
+++ b/libgo/go/net/lookup.go
@@ -0,0 +1,38 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+	"os"
+)
+
+// LookupHost looks up the given host using the local resolver.
+// It returns an array of that host's addresses.
+func LookupHost(host string) (addrs []string, err os.Error) {
+	addrs, err, ok := cgoLookupHost(host)
+	if !ok {
+		addrs, err = goLookupHost(host)
+	}
+	return
+}
+
+// LookupIP looks up host using the local resolver.
+// It returns an array of that host's IPv4 and IPv6 addresses.
+func LookupIP(host string) (addrs []IP, err os.Error) {
+	addrs, err, ok := cgoLookupIP(host)
+	if !ok {
+		addrs, err = goLookupIP(host)
+	}
+	return
+}
+
+// LookupPort looks up the port for the given network and service.
+func LookupPort(network, service string) (port int, err os.Error) {
+	port, err, ok := cgoLookupPort(network, service)
+	if !ok {
+		port, err = goLookupPort(network, service)
+	}
+	return
+}
diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go
index 275b31c0e31..da7928351ce 100644
--- a/libgo/go/net/net_test.go
+++ b/libgo/go/net/net_test.go
@@ -15,50 +15,49 @@ var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check f
 
 type DialErrorTest struct {
 	Net     string
-	Laddr   string
 	Raddr   string
 	Pattern string
 }
 
 var dialErrorTests = []DialErrorTest{
 	{
-		"datakit", "", "mh/astro/r70",
+		"datakit", "mh/astro/r70",
 		"dial datakit mh/astro/r70: unknown network datakit",
 	},
 	{
-		"tcp", "", "127.0.0.1:☺",
+		"tcp", "127.0.0.1:☺",
 		"dial tcp 127.0.0.1:☺: unknown port tcp/☺",
 	},
 	{
-		"tcp", "", "no-such-name.google.com.:80",
+		"tcp", "no-such-name.google.com.:80",
 		"dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
 	},
 	{
-		"tcp", "", "no-such-name.no-such-top-level-domain.:80",
+		"tcp", "no-such-name.no-such-top-level-domain.:80",
 		"dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
 	},
 	{
-		"tcp", "", "no-such-name:80",
+		"tcp", "no-such-name:80",
 		`dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
 	},
 	{
-		"tcp", "", "mh/astro/r70:http",
+		"tcp", "mh/astro/r70:http",
 		"dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
 	},
 	{
-		"unix", "", "/etc/file-not-found",
+		"unix", "/etc/file-not-found",
 		"dial unix /etc/file-not-found: [nN]o such file or directory",
 	},
 	{
-		"unix", "", "/etc/",
-		"dial unix /etc/: ([pP]ermission denied|[sS]ocket operation on non-socket|[cC]onnection refused)",
+		"unix", "/etc/",
+		"dial unix /etc/: ([pP]ermission denied|socket operation on non-socket|connection refused)",
 	},
 	{
-		"unixpacket", "", "/etc/file-not-found",
+		"unixpacket", "/etc/file-not-found",
 		"dial unixpacket /etc/file-not-found: no such file or directory",
 	},
 	{
-		"unixpacket", "", "/etc/",
+		"unixpacket", "/etc/",
 		"dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
 	},
 }
@@ -69,7 +68,7 @@ func TestDialError(t *testing.T) {
 		return
 	}
 	for i, tt := range dialErrorTests {
-		c, e := Dial(tt.Net, tt.Laddr, tt.Raddr)
+		c, e := Dial(tt.Net, tt.Raddr)
 		if c != nil {
 			c.Close()
 		}
diff --git a/libgo/go/net/port.go b/libgo/go/net/port.go
index 7d25058b29c..8f8327a3733 100644
--- a/libgo/go/net/port.go
+++ b/libgo/go/net/port.go
@@ -50,8 +50,8 @@ func readServices() {
 	file.close()
 }
 
-// LookupPort looks up the port for the given network and service.
-func LookupPort(network, service string) (port int, err os.Error) {
+// goLookupPort is the native Go implementation of LookupPort.
+func goLookupPort(network, service string) (port int, err os.Error) {
 	onceReadServices.Do(readServices)
 
 	switch network {
diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go
index 3dda500e585..37695a068d1 100644
--- a/libgo/go/net/server_test.go
+++ b/libgo/go/net/server_test.go
@@ -54,13 +54,15 @@ func runServe(t *testing.T, network, addr string, listening chan<- string, done
 }
 
 func connect(t *testing.T, network, addr string, isEmpty bool) {
-	var laddr string
+	var fd Conn
+	var err os.Error
 	if network == "unixgram" {
-		laddr = addr + ".local"
+		fd, err = DialUnix(network, &UnixAddr{addr + ".local", network}, &UnixAddr{addr, network})
+	} else {
+		fd, err = Dial(network, addr)
 	}
-	fd, err := Dial(network, laddr, addr)
 	if err != nil {
-		t.Fatalf("net.Dial(%q, %q, %q) = _, %v", network, laddr, addr, err)
+		t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err)
 	}
 	fd.SetReadTimeout(1e9) // 1s
 
diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go
index 5a88ddcbc29..933700af160 100644
--- a/libgo/go/net/sock.go
+++ b/libgo/go/net/sock.go
@@ -52,14 +52,16 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
 		}
 	}
 
+	if fd, err = newFD(s, f, p, net); err != nil {
+		closesocket(s)
+		return nil, err
+	}
+
 	if ra != nil {
-		e = syscall.Connect(s, ra)
-		for e == syscall.EINTR {
-			e = syscall.Connect(s, ra)
-		}
-		if e != 0 {
+		if err = fd.connect(ra); err != nil {
+			fd.sysfd = -1
 			closesocket(s)
-			return nil, os.Errno(e)
+			return nil, err
 		}
 	}
 
@@ -68,12 +70,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
 	sa, _ = syscall.Getpeername(s)
 	raddr := toAddr(sa)
 
-	fd, err = newFD(s, f, p, net, laddr, raddr)
-	if err != nil {
-		closesocket(s)
-		return nil, err
-	}
-
+	fd.setAddr(laddr, raddr)
 	return fd, nil
 }
 
@@ -170,9 +167,9 @@ func (e *UnknownSocketError) String() string {
 func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) {
 	switch a := sa.(type) {
 	case *syscall.SockaddrInet4:
-		return joinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
+		return JoinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
 	case *syscall.SockaddrInet6:
-		return joinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
+		return JoinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
 	case *syscall.SockaddrUnix:
 		return a.Name, nil
 	}
diff --git a/libgo/go/net/tcpsock.go b/libgo/go/net/tcpsock.go
index a4bca11bb48..b484be20b46 100644
--- a/libgo/go/net/tcpsock.go
+++ b/libgo/go/net/tcpsock.go
@@ -34,7 +34,7 @@ func (a *TCPAddr) String() string {
 	if a == nil {
 		return ""
 	}
-	return joinHostPort(a.IP.String(), itoa(a.Port))
+	return JoinHostPort(a.IP.String(), itoa(a.Port))
 }
 
 func (a *TCPAddr) family() int {
@@ -213,8 +213,9 @@ func (c *TCPConn) SetNoDelay(noDelay bool) os.Error {
 // Closing c does not affect f, and closing f does not affect c.
 func (c *TCPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
 
-// DialTCP is like Dial but can only connect to TCP networks
-// and returns a TCPConn structure.
+// DialTCP connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is used
+// as the local address for the connection.
 func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
 	if raddr == nil {
 		return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
diff --git a/libgo/go/net/textproto/textproto.go b/libgo/go/net/textproto/textproto.go
index f62009c523b..fbfad9d61ce 100644
--- a/libgo/go/net/textproto/textproto.go
+++ b/libgo/go/net/textproto/textproto.go
@@ -78,7 +78,7 @@ func (c *Conn) Close() os.Error {
 // Dial connects to the given address on the given network using net.Dial
 // and then returns a new Conn for the connection.
 func Dial(network, addr string) (*Conn, os.Error) {
-	c, err := net.Dial(network, "", addr)
+	c, err := net.Dial(network, addr)
 	if err != nil {
 		return nil, err
 	}
diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go
index 09a257dc817..0dbab5846a6 100644
--- a/libgo/go/net/timeout_test.go
+++ b/libgo/go/net/timeout_test.go
@@ -11,7 +11,7 @@ import (
 )
 
 func testTimeout(t *testing.T, network, addr string, readFrom bool) {
-	fd, err := Dial(network, "", addr)
+	fd, err := Dial(network, addr)
 	if err != nil {
 		t.Errorf("dial %s %s failed: %v", network, addr, err)
 		return
diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go
index f9274493e60..44d618dab08 100644
--- a/libgo/go/net/udpsock.go
+++ b/libgo/go/net/udpsock.go
@@ -34,7 +34,7 @@ func (a *UDPAddr) String() string {
 	if a == nil {
 		return ""
 	}
-	return joinHostPort(a.IP.String(), itoa(a.Port))
+	return JoinHostPort(a.IP.String(), itoa(a.Port))
 }
 
 func (a *UDPAddr) family() int {
diff --git a/libgo/go/netchan/import.go b/libgo/go/netchan/import.go
index 5db679a3ed6..8ba5df9a515 100644
--- a/libgo/go/netchan/import.go
+++ b/libgo/go/netchan/import.go
@@ -48,7 +48,7 @@ func NewImporter(conn io.ReadWriter) *Importer {
 
 // Import imports a set of channels from the given network and address.
 func Import(network, remoteaddr string) (*Importer, os.Error) {
-	conn, err := net.Dial(network, "", remoteaddr)
+	conn, err := net.Dial(network, remoteaddr)
 	if err != nil {
 		return nil, err
 	}
diff --git a/libgo/go/netchan/netchan_test.go b/libgo/go/netchan/netchan_test.go
index 1b5c560872e..fd4d8f780d9 100644
--- a/libgo/go/netchan/netchan_test.go
+++ b/libgo/go/netchan/netchan_test.go
@@ -399,7 +399,7 @@ func TestImportFlowControl(t *testing.T) {
 
 func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) {
 	go func() {
-		time.Sleep(1e9)
+		time.Sleep(0.5e9)
 		sendDone <- false
 	}()
 
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
index 57d4a477fc6..01268e53a78 100644
--- a/libgo/go/os/file_unix.go
+++ b/libgo/go/os/file_unix.go
@@ -108,3 +108,21 @@ func Truncate(name string, size int64) Error {
 	}
 	return nil
 }
+
+// basename removes trailing slashes and the leading directory name from path name
+func basename(name string) string {
+	i := len(name) - 1
+	// Remove trailing slashes
+	for ; i > 0 && name[i] == '/'; i-- {
+		name = name[:i]
+	}
+	// Remove leading directory name
+	for i--; i >= 0; i-- {
+		if name[i] == '/' {
+			name = name[i+1:]
+			break
+		}
+	}
+
+	return name
+}
diff --git a/libgo/go/rpc/client.go b/libgo/go/rpc/client.go
index 92372521175..8af4afcf697 100644
--- a/libgo/go/rpc/client.go
+++ b/libgo/go/rpc/client.go
@@ -208,7 +208,7 @@ func DialHTTP(network, address string) (*Client, os.Error) {
 // at the specified network address and path.
 func DialHTTPPath(network, address, path string) (*Client, os.Error) {
 	var err os.Error
-	conn, err := net.Dial(network, "", address)
+	conn, err := net.Dial(network, address)
 	if err != nil {
 		return nil, err
 	}
@@ -229,7 +229,7 @@ func DialHTTPPath(network, address, path string) (*Client, os.Error) {
 
 // Dial connects to an RPC server at the specified network address.
 func Dial(network, address string) (*Client, os.Error) {
-	conn, err := net.Dial(network, "", address)
+	conn, err := net.Dial(network, address)
 	if err != nil {
 		return nil, err
 	}
diff --git a/libgo/go/rpc/jsonrpc/client.go b/libgo/go/rpc/jsonrpc/client.go
index 5b806bd6e25..57e977d3253 100644
--- a/libgo/go/rpc/jsonrpc/client.go
+++ b/libgo/go/rpc/jsonrpc/client.go
@@ -116,7 +116,7 @@ func NewClient(conn io.ReadWriteCloser) *rpc.Client {
 
 // Dial connects to a JSON-RPC server at the specified network address.
 func Dial(network, address string) (*rpc.Client, os.Error) {
-	conn, err := net.Dial(network, "", address)
+	conn, err := net.Dial(network, address)
 	if err != nil {
 		return nil, err
 	}
diff --git a/libgo/go/runtime/pprof/pprof_test.go b/libgo/go/runtime/pprof/pprof_test.go
index 603465eaa52..a060917a280 100644
--- a/libgo/go/runtime/pprof/pprof_test.go
+++ b/libgo/go/runtime/pprof/pprof_test.go
@@ -15,7 +15,15 @@ import (
 )
 
 func TestCPUProfile(t *testing.T) {
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+	switch runtime.GOOS {
+	case "darwin":
+		// see Apple Bug Report #9177434 (copied into change description)
+		return
+	case "plan9":
+		// unimplemented
+		return
+	case "windows":
+		// unimplemented
 		return
 	}
 
diff --git a/libgo/go/smtp/smtp.go b/libgo/go/smtp/smtp.go
index 2f6d2f31a78..3f89af14720 100644
--- a/libgo/go/smtp/smtp.go
+++ b/libgo/go/smtp/smtp.go
@@ -39,7 +39,7 @@ type Client struct {
 
 // Dial returns a new Client connected to an SMTP server at addr.
 func Dial(addr string) (*Client, os.Error) {
-	conn, err := net.Dial("tcp", "", addr)
+	conn, err := net.Dial("tcp", addr)
 	if err != nil {
 		return nil, err
 	}
diff --git a/libgo/go/sort/sort_test.go b/libgo/go/sort/sort_test.go
index 1bea8f03262..3d7337fd010 100644
--- a/libgo/go/sort/sort_test.go
+++ b/libgo/go/sort/sort_test.go
@@ -74,7 +74,11 @@ func TestSortStrings(t *testing.T) {
 }
 
 func TestSortLarge_Random(t *testing.T) {
-	data := make([]int, 1000000)
+	n := 1000000
+	if testing.Short() {
+		n /= 100
+	}
+	data := make([]int, n)
 	for i := 0; i < len(data); i++ {
 		data[i] = rand.Intn(100)
 	}
@@ -174,6 +178,9 @@ func lg(n int) int {
 
 func TestBentleyMcIlroy(t *testing.T) {
 	sizes := []int{100, 1023, 1024, 1025}
+	if testing.Short() {
+		sizes = []int{100, 127, 128, 129}
+	}
 	dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"}
 	modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"}
 	var tmp1, tmp2 [1025]int
diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go
index 5f009e54859..93c7c464738 100644
--- a/libgo/go/strings/strings.go
+++ b/libgo/go/strings/strings.go
@@ -275,20 +275,10 @@ func Join(a []string, sep string) string {
 	}
 
 	b := make([]byte, n)
-	bp := 0
-	for i := 0; i < len(a); i++ {
-		s := a[i]
-		for j := 0; j < len(s); j++ {
-			b[bp] = s[j]
-			bp++
-		}
-		if i+1 < len(a) {
-			s = sep
-			for j := 0; j < len(s); j++ {
-				b[bp] = s[j]
-				bp++
-			}
-		}
+	bp := copy(b, a[0])
+	for _, s := range a[1:] {
+		bp += copy(b[bp:], sep)
+		bp += copy(b[bp:], s)
 	}
 	return string(b)
 }
@@ -312,9 +302,19 @@ func Map(mapping func(rune int) int, s string) string {
 	// fine.  It could also shrink but that falls out naturally.
 	maxbytes := len(s) // length of b
 	nbytes := 0        // number of bytes encoded in b
-	b := make([]byte, maxbytes)
-	for _, c := range s {
+	// The output buffer b is initialized on demand, the first
+	// time a character differs.
+	var b []byte
+
+	for i, c := range s {
 		rune := mapping(c)
+		if b == nil {
+			if rune == c {
+				continue
+			}
+			b = make([]byte, maxbytes)
+			nbytes = copy(b, s[:i])
+		}
 		if rune >= 0 {
 			wid := 1
 			if rune >= utf8.RuneSelf {
@@ -330,6 +330,9 @@ func Map(mapping func(rune int) int, s string) string {
 			nbytes += utf8.EncodeRune(b[nbytes:maxbytes], rune)
 		}
 	}
+	if b == nil {
+		return s
+	}
 	return string(b[0:nbytes])
 }
 
diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go
index 41e398782e6..c45b1485d8f 100644
--- a/libgo/go/strings/strings_test.go
+++ b/libgo/go/strings/strings_test.go
@@ -6,10 +6,12 @@ package strings_test
 
 import (
 	"os"
+	"reflect"
 	"strconv"
 	. "strings"
 	"testing"
 	"unicode"
+	"unsafe"
 	"utf8"
 )
 
@@ -429,12 +431,32 @@ func TestMap(t *testing.T) {
 	if m != expect {
 		t.Errorf("drop: expected %q got %q", expect, m)
 	}
+
+	// 6. Identity
+	identity := func(rune int) int {
+		return rune
+	}
+	orig := "Input string that we expect not to be copied."
+	m = Map(identity, orig)
+	if (*reflect.StringHeader)(unsafe.Pointer(&orig)).Data !=
+		(*reflect.StringHeader)(unsafe.Pointer(&m)).Data {
+		t.Error("unexpected copy during identity map")
+	}
 }
 
 func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
 
 func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTests) }
 
+func BenchmarkMapNoChanges(b *testing.B) {
+	identity := func(rune int) int {
+		return rune
+	}
+	for i := 0; i < b.N; i++ {
+		Map(identity, "Some string that won't be modified.")
+	}
+}
+
 func TestSpecialCase(t *testing.T) {
 	lower := "abcçdefgğhıijklmnoöprsştuüvyz"
 	upper := "ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ"
@@ -617,7 +639,11 @@ func equal(m string, s1, s2 string, t *testing.T) bool {
 
 func TestCaseConsistency(t *testing.T) {
 	// Make a string of all the runes.
-	a := make([]int, unicode.MaxRune+1)
+	numRunes := unicode.MaxRune + 1
+	if testing.Short() {
+		numRunes = 1000
+	}
+	a := make([]int, numRunes)
 	for i := range a {
 		a[i] = i
 	}
@@ -627,10 +653,10 @@ func TestCaseConsistency(t *testing.T) {
 	lower := ToLower(s)
 
 	// Consistency checks
-	if n := utf8.RuneCountInString(upper); n != unicode.MaxRune+1 {
+	if n := utf8.RuneCountInString(upper); n != numRunes {
 		t.Error("rune count wrong in upper:", n)
 	}
-	if n := utf8.RuneCountInString(lower); n != unicode.MaxRune+1 {
+	if n := utf8.RuneCountInString(lower); n != numRunes {
 		t.Error("rune count wrong in lower:", n)
 	}
 	if !equal("ToUpper(upper)", ToUpper(upper), upper, t) {
diff --git a/libgo/go/sync/atomic/atomic_test.go b/libgo/go/sync/atomic/atomic_test.go
index 7b204b1d9f0..119ad0036fd 100644
--- a/libgo/go/sync/atomic/atomic_test.go
+++ b/libgo/go/sync/atomic/atomic_test.go
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package atomic
+package atomic_test
 
 import (
 	"runtime"
+	. "sync/atomic"
 	"testing"
 	"unsafe"
 )
@@ -27,6 +28,16 @@ const (
 	magic64 = 0xdeddeadbeefbeef
 )
 
+// Do the 64-bit functions panic?  If so, don't bother testing.
+var test64err = func() (err interface{}) {
+	defer func() {
+		err = recover()
+	}()
+	var x int64
+	AddInt64(&x, 1)
+	return nil
+}()
+
 func TestAddInt32(t *testing.T) {
 	var x struct {
 		before int32
@@ -70,6 +81,10 @@ func TestAddUint32(t *testing.T) {
 }
 
 func TestAddInt64(t *testing.T) {
+	if test64err != nil {
+		t.Logf("Skipping 64-bit tests: %v", test64err)
+		return
+	}
 	var x struct {
 		before int64
 		i      int64
@@ -91,6 +106,10 @@ func TestAddInt64(t *testing.T) {
 }
 
 func TestAddUint64(t *testing.T) {
+	if test64err != nil {
+		t.Logf("Skipping 64-bit tests: %v", test64err)
+		return
+	}
 	var x struct {
 		before uint64
 		i      uint64
@@ -193,6 +212,10 @@ func TestCompareAndSwapUint32(t *testing.T) {
 }
 
 func TestCompareAndSwapInt64(t *testing.T) {
+	if test64err != nil {
+		t.Logf("Skipping 64-bit tests: %v", test64err)
+		return
+	}
 	var x struct {
 		before int64
 		i      int64
@@ -222,6 +245,10 @@ func TestCompareAndSwapInt64(t *testing.T) {
 }
 
 func TestCompareAndSwapUint64(t *testing.T) {
+	if test64err != nil {
+		t.Logf("Skipping 64-bit tests: %v", test64err)
+		return
+	}
 	var x struct {
 		before uint64
 		i      uint64
@@ -370,10 +397,11 @@ func hammerCompareAndSwapUintptr32(uval *uint32, count int) {
 }
 
 func TestHammer32(t *testing.T) {
-	const (
-		n = 100000
-		p = 4
-	)
+	const p = 4
+	n := 100000
+	if testing.Short() {
+		n = 1000
+	}
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p))
 
 	for _, tt := range hammer32 {
@@ -391,7 +419,7 @@ func TestHammer32(t *testing.T) {
 		for i := 0; i < p; i++ {
 			<-c
 		}
-		if val != n*p {
+		if val != uint32(n)*p {
 			t.Errorf("%s: val=%d want %d", tt.name, val, n*p)
 		}
 	}
@@ -478,10 +506,15 @@ func hammerCompareAndSwapUintptr64(uval *uint64, count int) {
 }
 
 func TestHammer64(t *testing.T) {
-	const (
-		n = 100000
-		p = 4
-	)
+	if test64err != nil {
+		t.Logf("Skipping 64-bit tests: %v", test64err)
+		return
+	}
+	const p = 4
+	n := 100000
+	if testing.Short() {
+		n = 1000
+	}
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(p))
 
 	for _, tt := range hammer64 {
@@ -499,7 +532,7 @@ func TestHammer64(t *testing.T) {
 		for i := 0; i < p; i++ {
 			<-c
 		}
-		if val != n*p {
+		if val != uint64(n)*p {
 			t.Errorf("%s: val=%d want %d", tt.name, val, n*p)
 		}
 	}
diff --git a/libgo/go/sync/atomic/doc.go b/libgo/go/sync/atomic/doc.go
index 1335def59f6..ec5a0d33af1 100644
--- a/libgo/go/sync/atomic/doc.go
+++ b/libgo/go/sync/atomic/doc.go
@@ -55,3 +55,8 @@ func AddUint64(val *uint64, delta uint64) (new uint64)
 
 // AddUintptr atomically adds delta to *val and returns the new value.
 func AddUintptr(val *uintptr, delta uintptr) (new uintptr)
+
+// Helper for ARM.  Linker will discard on other systems
+func panic64() {
+	panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)")
+}
diff --git a/libgo/go/sync/rwmutex_test.go b/libgo/go/sync/rwmutex_test.go
index 405079270dc..9fb89f8e8a3 100644
--- a/libgo/go/sync/rwmutex_test.go
+++ b/libgo/go/sync/rwmutex_test.go
@@ -102,16 +102,20 @@ func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) {
 }
 
 func TestRWMutex(t *testing.T) {
-	HammerRWMutex(1, 1, 1000)
-	HammerRWMutex(1, 3, 1000)
-	HammerRWMutex(1, 10, 1000)
-	HammerRWMutex(4, 1, 1000)
-	HammerRWMutex(4, 3, 1000)
-	HammerRWMutex(4, 10, 1000)
-	HammerRWMutex(10, 1, 1000)
-	HammerRWMutex(10, 3, 1000)
-	HammerRWMutex(10, 10, 1000)
-	HammerRWMutex(10, 5, 10000)
+	n := 1000
+	if testing.Short() {
+		n = 5
+	}
+	HammerRWMutex(1, 1, n)
+	HammerRWMutex(1, 3, n)
+	HammerRWMutex(1, 10, n)
+	HammerRWMutex(4, 1, n)
+	HammerRWMutex(4, 3, n)
+	HammerRWMutex(4, 10, n)
+	HammerRWMutex(10, 1, n)
+	HammerRWMutex(10, 3, n)
+	HammerRWMutex(10, 10, n)
+	HammerRWMutex(10, 5, n)
 }
 
 func TestRLocker(t *testing.T) {
diff --git a/libgo/go/syslog/syslog.go b/libgo/go/syslog/syslog.go
index 711d5ddc74e..4ada113f1d7 100644
--- a/libgo/go/syslog/syslog.go
+++ b/libgo/go/syslog/syslog.go
@@ -67,7 +67,7 @@ func Dial(network, raddr string, priority Priority, prefix string) (w *Writer, e
 		conn, err = unixSyslog()
 	} else {
 		var c net.Conn
-		c, err = net.Dial(network, "", raddr)
+		c, err = net.Dial(network, raddr)
 		conn = netConn{c}
 	}
 	return &Writer{priority, prefix, conn}, err
diff --git a/libgo/go/syslog/syslog_unix.go b/libgo/go/syslog/syslog_unix.go
index b4daf88ee28..fa15e882d07 100644
--- a/libgo/go/syslog/syslog_unix.go
+++ b/libgo/go/syslog/syslog_unix.go
@@ -19,7 +19,7 @@ func unixSyslog() (conn serverConn, err os.Error) {
 	for _, network := range logTypes {
 		for _, path := range logPaths {
 			raddr = path
-			conn, err := net.Dial(network, "", raddr)
+			conn, err := net.Dial(network, raddr)
 			if err != nil {
 				continue
 			} else {
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index ab8cf999a25..d1893907a56 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -48,6 +48,13 @@ import (
 )
 
 var (
+	// The short flag requests that tests run more quickly, but its functionality
+	// is provided by test writers themselves.  The testing package is just its
+	// home.  The all.bash installation script sets it to make installation more
+	// efficient, but by default the flag is off so a plain "gotest" will do a
+	// full test of the package.
+	short = flag.Bool("test.short", false, "run smaller test suite to save time")
+
 	// Report as tests are run; default is silent for success.
 	chatty         = flag.Bool("test.v", false, "verbose: print additional output")
 	match          = flag.String("test.run", "", "regular expression to select tests to run")
@@ -56,6 +63,11 @@ var (
 	cpuProfile     = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
 )
 
+// Short reports whether the -test.short flag is set.
+func Short() bool {
+	return *short
+}
+
 
 // Insert final newline if needed and tabs after internal newlines.
 func tabify(s string) string {
@@ -174,7 +186,7 @@ func RunTests(matchString func(pat, str string) (bool, os.Error), tests []Intern
 		go tRunner(t, &tests[i])
 		<-t.ch
 		ns += time.Nanoseconds()
-		tstr := fmt.Sprintf("(%.1f seconds)", float64(ns)/1e9)
+		tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9)
 		if t.failed {
 			println("--- FAIL:", tests[i].Name, tstr)
 			print(t.errors)
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
index 5fe4d7f15b5..eb6bb25fd4d 100644
--- a/libgo/go/time/sleep_test.go
+++ b/libgo/go/time/sleep_test.go
@@ -5,6 +5,7 @@
 package time_test
 
 import (
+	"fmt"
 	"os"
 	"syscall"
 	"testing"
@@ -132,8 +133,22 @@ func TestAfterStop(t *testing.T) {
 	}
 }
 
+func TestAfterQueuing(t *testing.T) {
+	// This test flakes out on some systems,
+	// so we'll try it a few times before declaring it a failure.
+	const attempts = 3
+	err := os.NewError("!=nil")
+	for i := 0; i < attempts && err != nil; i++ {
+		if err = testAfterQueuing(t); err != nil {
+			t.Logf("attempt %v failed: %v", i, err)
+		}
+	}
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
 // For gccgo omit 0 for now because it can take too long to start the
-// thread.
 var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8, /*0*/}
 
 type afterResult struct {
@@ -145,7 +160,7 @@ func await(slot int, result chan<- afterResult, ac <-chan int64) {
 	result <- afterResult{slot, <-ac}
 }
 
-func TestAfterQueuing(t *testing.T) {
+func testAfterQueuing(t *testing.T) os.Error {
 	const (
 		Delta = 100 * 1e6
 	)
@@ -162,13 +177,14 @@ func TestAfterQueuing(t *testing.T) {
 	for _, slot := range slots {
 		r := <-result
 		if r.slot != slot {
-			t.Fatalf("after queue got slot %d, expected %d", r.slot, slot)
+			return fmt.Errorf("after queue got slot %d, expected %d", r.slot, slot)
 		}
 		ns := r.t - t0
 		target := int64(slot * Delta)
 		slop := int64(Delta) / 4
 		if ns < target-slop || ns > target+slop {
-			t.Fatalf("after queue slot %d arrived at %g, expected [%g,%g]", slot, float64(ns), float64(target-slop), float64(target+slop))
+			return fmt.Errorf("after queue slot %d arrived at %g, expected [%g,%g]", slot, float64(ns), float64(target-slop), float64(target+slop))
 		}
 	}
+	return nil
 }
diff --git a/libgo/go/utf8/string_test.go b/libgo/go/utf8/string_test.go
index 9dd84724730..f376b628c73 100644
--- a/libgo/go/utf8/string_test.go
+++ b/libgo/go/utf8/string_test.go
@@ -45,7 +45,12 @@ func TestScanBackwards(t *testing.T) {
 	}
 }
 
-const randCount = 100000
+func randCount() int {
+	if testing.Short() {
+		return 100
+	}
+	return 100000
+}
 
 func TestRandomAccess(t *testing.T) {
 	for _, s := range testStrings {
@@ -58,7 +63,7 @@ func TestRandomAccess(t *testing.T) {
 			t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
 			break
 		}
-		for j := 0; j < randCount; j++ {
+		for j := 0; j < randCount(); j++ {
 			i := rand.Intn(len(runes))
 			expect := runes[i]
 			got := str.At(i)
@@ -80,7 +85,7 @@ func TestRandomSliceAccess(t *testing.T) {
 			t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
 			break
 		}
-		for k := 0; k < randCount; k++ {
+		for k := 0; k < randCount(); k++ {
 			i := rand.Intn(len(runes))
 			j := rand.Intn(len(runes) + 1)
 			if i > j { // include empty strings
diff --git a/libgo/go/websocket/client.go b/libgo/go/websocket/client.go
index d8a7aa0a266..78c8b7f57bf 100644
--- a/libgo/go/websocket/client.go
+++ b/libgo/go/websocket/client.go
@@ -108,10 +108,10 @@ func Dial(url, protocol, origin string) (ws *Conn, err os.Error) {
 
 	switch parsedUrl.Scheme {
 	case "ws":
-		client, err = net.Dial("tcp", "", parsedUrl.Host)
+		client, err = net.Dial("tcp", parsedUrl.Host)
 
 	case "wss":
-		client, err = tls.Dial("tcp", "", parsedUrl.Host, nil)
+		client, err = tls.Dial("tcp", parsedUrl.Host, nil)
 
 	default:
 		err = ErrBadScheme
diff --git a/libgo/go/websocket/websocket_test.go b/libgo/go/websocket/websocket_test.go
index 14d708a3bab..8b3cf8925a9 100644
--- a/libgo/go/websocket/websocket_test.go
+++ b/libgo/go/websocket/websocket_test.go
@@ -53,7 +53,7 @@ func TestEcho(t *testing.T) {
 	once.Do(startServer)
 
 	// websocket.Dial()
-	client, err := net.Dial("tcp", "", serverAddr)
+	client, err := net.Dial("tcp", serverAddr)
 	if err != nil {
 		t.Fatal("dialing", err)
 	}
@@ -84,7 +84,7 @@ func TestEchoDraft75(t *testing.T) {
 	once.Do(startServer)
 
 	// websocket.Dial()
-	client, err := net.Dial("tcp", "", serverAddr)
+	client, err := net.Dial("tcp", serverAddr)
 	if err != nil {
 		t.Fatal("dialing", err)
 	}
@@ -114,7 +114,7 @@ func TestEchoDraft75(t *testing.T) {
 func TestWithQuery(t *testing.T) {
 	once.Do(startServer)
 
-	client, err := net.Dial("tcp", "", serverAddr)
+	client, err := net.Dial("tcp", serverAddr)
 	if err != nil {
 		t.Fatal("dialing", err)
 	}
@@ -131,7 +131,7 @@ func TestWithQuery(t *testing.T) {
 func TestWithProtocol(t *testing.T) {
 	once.Do(startServer)
 
-	client, err := net.Dial("tcp", "", serverAddr)
+	client, err := net.Dial("tcp", serverAddr)
 	if err != nil {
 		t.Fatal("dialing", err)
 	}
@@ -200,7 +200,7 @@ func TestSmallBuffer(t *testing.T) {
 	once.Do(startServer)
 
 	// websocket.Dial()
-	client, err := net.Dial("tcp", "", serverAddr)
+	client, err := net.Dial("tcp", serverAddr)
 	if err != nil {
 		t.Fatal("dialing", err)
 	}
diff --git a/libgo/syscalls/socket.go b/libgo/syscalls/socket.go
index e786653705b..28581a523e0 100644
--- a/libgo/syscalls/socket.go
+++ b/libgo/syscalls/socket.go
@@ -208,6 +208,13 @@ func Listen(fd int, n int) (errno int) {
   return;
 }
 
+func GetsockoptInt(fd, level, opt int) (value, errno int) {
+	var n int32
+	vallen := Socklen_t(4)
+	errno = libc_getsockopt(fd, level, opt, (*byte)(unsafe.Pointer(&n)), &vallen)
+	return int(n), errno
+}
+
 func setsockopt(fd, level, opt int, valueptr uintptr, length Socklen_t) (errno int) {
   r := libc_setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(valueptr)),
 		       length);
@@ -383,5 +390,3 @@ func Shutdown(fd int, how int) (errno int) {
 	if r < 0 { errno = GetErrno() }
 	return;
 }
-
-// FIXME: No getsockopt.
diff --git a/libgo/syscalls/sysfile_posix.go b/libgo/syscalls/sysfile_posix.go
index 8b724983c63..46ac0e07e1d 100644
--- a/libgo/syscalls/sysfile_posix.go
+++ b/libgo/syscalls/sysfile_posix.go
@@ -209,7 +209,7 @@ func FDZero(set *FdSet_t) {
 
 func Select(nfds int, r *FdSet_t, w *FdSet_t, e *FdSet_t, timeout *Timeval) (n int, errno int) {
   n = libc_select(nfds, (*byte)(unsafe.Pointer(r)),
-		  (*byte)(unsafe.Pointer(e)),
+		  (*byte)(unsafe.Pointer(w)),
 		  (*byte)(unsafe.Pointer(e)), timeout);
   if n < 0 { errno = GetErrno() }
   return;
diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest
index 20ae0a0bd25..bcd725136b9 100755
--- a/libgo/testsuite/gotest
+++ b/libgo/testsuite/gotest
@@ -357,7 +357,7 @@ case "x$dejagnu" in
 xno)
 	${GC} -g -c _testmain.go
 	${GL} *.o ${GOLIBS}
-	./a.out "$@"
+	./a.out -test.short "$@"
 	;;
 xyes)
 	rm -rf ../testsuite/*.o
diff --git a/libgo/testsuite/libgo.testmain/testmain.exp b/libgo/testsuite/libgo.testmain/testmain.exp
index efdd28d9162..f201de7f76a 100644
--- a/libgo/testsuite/libgo.testmain/testmain.exp
+++ b/libgo/testsuite/libgo.testmain/testmain.exp
@@ -54,7 +54,7 @@ if ![ string match "" $comp_output ] {
     exit 1
 }
 
-set result [libgo_load "./a.exe" "" ""]
+set result [libgo_load "./a.exe" "-test.short" ""]
 
 set status [lindex $result 0]
 $status go