diff --git a/src/bytes/reader.go b/src/bytes/reader.go index 08464c2402d74..5946cf9780b0e 100644 --- a/src/bytes/reader.go +++ b/src/bytes/reader.go @@ -14,6 +14,7 @@ import ( // io.ByteScanner, and io.RuneScanner interfaces by reading from // a byte slice. // Unlike a Buffer, a Reader is read-only and supports seeking. +// The zero value for Reader operates like a Reader of an empty slice. type Reader struct { s []byte i int64 // current reading index @@ -75,10 +76,10 @@ func (r *Reader) ReadByte() (byte, error) { // UnreadByte complements ReadByte in implementing the io.ByteScanner interface. func (r *Reader) UnreadByte() error { - r.prevRune = -1 if r.i <= 0 { return errors.New("bytes.Reader.UnreadByte: at beginning of slice") } + r.prevRune = -1 r.i-- return nil } @@ -101,6 +102,9 @@ func (r *Reader) ReadRune() (ch rune, size int, err error) { // UnreadRune complements ReadRune in implementing the io.RuneScanner interface. func (r *Reader) UnreadRune() error { + if r.i <= 0 { + return errors.New("bytes.Reader.UnreadRune: at beginning of slice") + } if r.prevRune < 0 { return errors.New("bytes.Reader.UnreadRune: previous operation was not ReadRune") } diff --git a/src/bytes/reader_test.go b/src/bytes/reader_test.go index 8806876ff13c7..d799e036f0c00 100644 --- a/src/bytes/reader_test.go +++ b/src/bytes/reader_test.go @@ -276,3 +276,45 @@ func TestReaderReset(t *testing.T) { t.Errorf("ReadAll: got %q, want %q", got, want) } } + +func TestReaderZero(t *testing.T) { + if l := (&Reader{}).Len(); l != 0 { + t.Errorf("Len: got %d, want 0", l) + } + + if n, err := (&Reader{}).Read(nil); n != 0 || err != io.EOF { + t.Errorf("Read: got %d, %v; want 0, io.EOF", n, err) + } + + if n, err := (&Reader{}).ReadAt(nil, 11); n != 0 || err != io.EOF { + t.Errorf("ReadAt: got %d, %v; want 0, io.EOF", n, err) + } + + if b, err := (&Reader{}).ReadByte(); b != 0 || err != io.EOF { + t.Errorf("ReadByte: got %d, %v; want 0, io.EOF", b, err) + } + + if ch, size, err := (&Reader{}).ReadRune(); ch != 0 || size != 0 || err != io.EOF { + t.Errorf("ReadRune: got %d, %d, %v; want 0, 0, io.EOF", ch, size, err) + } + + if offset, err := (&Reader{}).Seek(11, io.SeekStart); offset != 11 || err != nil { + t.Errorf("Seek: got %d, %v; want 11, nil", offset, err) + } + + if s := (&Reader{}).Size(); s != 0 { + t.Errorf("Size: got %d, want 0", s) + } + + if (&Reader{}).UnreadByte() == nil { + t.Errorf("UnreadByte: got nil, want error") + } + + if (&Reader{}).UnreadRune() == nil { + t.Errorf("UnreadRune: got nil, want error") + } + + if n, err := (&Reader{}).WriteTo(ioutil.Discard); n != 0 || err != nil { + t.Errorf("WriteTo: got %d, %v; want 0, nil", n, err) + } +} diff --git a/src/cmd/compile/doc.go b/src/cmd/compile/doc.go index bce03fc40fe22..e2a19d98c0be5 100644 --- a/src/cmd/compile/doc.go +++ b/src/cmd/compile/doc.go @@ -64,6 +64,9 @@ Flags: instead of $GOROOT/pkg/$GOOS_$GOARCH. -l Disable inlining. + -lang version + Set language version to compile, as in -lang=go1.12. + Default is current version. -largemodel Generate code that assumes a large memory model. -linkobj file diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 144a1f51f8fef..a2c7d5d8d8561 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -762,12 +762,20 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { sc := v.AuxValAndOff() off := sc.Off() val := sc.Val() - if val == 1 { + if val == 1 || val == -1 { var asm obj.As if v.Op == ssa.OpAMD64ADDQconstmodify { - asm = x86.AINCQ + if val == 1 { + asm = x86.AINCQ + } else { + asm = x86.ADECQ + } } else { - asm = x86.AINCL + if val == 1 { + asm = x86.AINCL + } else { + asm = x86.ADECL + } } p := s.Prog(asm) p.To.Type = obj.TYPE_MEM diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index 8051c7d0dfa05..325bf4aa0ec70 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -117,8 +117,8 @@ var runtimeDecls = [...]struct { {"selectsetpc", funcTag, 56}, {"selectgo", funcTag, 93}, {"block", funcTag, 5}, - {"makeslice", funcTag, 95}, - {"makeslice64", funcTag, 96}, + {"makeslice", funcTag, 94}, + {"makeslice64", funcTag, 95}, {"growslice", funcTag, 97}, {"memmove", funcTag, 98}, {"memclrNoHeapPointers", funcTag, 99}, @@ -249,10 +249,10 @@ func runtimeTypes() []*types.Type { typs[91] = types.NewPtr(typs[11]) typs[92] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[91]), anonfield(typs[79])}, []*Node{anonfield(typs[11])}) typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[32]), anonfield(typs[11])}) - typs[94] = types.NewSlice(typs[2]) - typs[95] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[94])}) - typs[96] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[94])}) - typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[94]), anonfield(typs[32])}, []*Node{anonfield(typs[94])}) + typs[94] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[58])}) + typs[95] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[58])}) + typs[96] = types.NewSlice(typs[2]) + typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[96]), anonfield(typs[32])}, []*Node{anonfield(typs[96])}) typs[98] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[47])}, nil) typs[99] = functype(nil, []*Node{anonfield(typs[58]), anonfield(typs[47])}, nil) typs[100] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[47])}, []*Node{anonfield(typs[11])}) diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index 028936b8758da..e6d174bc4b44a 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -153,8 +153,8 @@ func selectsetpc(cas *byte) func selectgo(cas0 *byte, order0 *byte, ncases int) (int, bool) func block() -func makeslice(typ *byte, len int, cap int) (ary []any) -func makeslice64(typ *byte, len int64, cap int64) (ary []any) +func makeslice(typ *byte, len int, cap int) unsafe.Pointer +func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer func growslice(typ *byte, old []any, cap int) (ary []any) func memmove(to *any, frm *any, length uintptr) func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) diff --git a/src/cmd/compile/internal/gc/lang_test.go b/src/cmd/compile/internal/gc/lang_test.go new file mode 100644 index 0000000000000..b225f03a1de1f --- /dev/null +++ b/src/cmd/compile/internal/gc/lang_test.go @@ -0,0 +1,59 @@ +// Copyright 2018 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 gc + +import ( + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "testing" +) + +const aliasSrc = ` +package x + +type T = int +` + +func TestInvalidLang(t *testing.T) { + t.Parallel() + + testenv.MustHaveGoBuild(t) + + dir, err := ioutil.TempDir("", "TestInvalidLang") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + src := filepath.Join(dir, "alias.go") + if err := ioutil.WriteFile(src, []byte(aliasSrc), 0644); err != nil { + t.Fatal(err) + } + + outfile := filepath.Join(dir, "alias.o") + + if testLang(t, "go9.99", src, outfile) == nil { + t.Error("compilation with -lang=go9.99 succeeded unexpectedly") + } + + if testLang(t, "go1.8", src, outfile) == nil { + t.Error("compilation with -lang=go1.8 succeeded unexpectedly") + } + + if err := testLang(t, "go1.9", src, outfile); err != nil { + t.Errorf("compilation with -lang=go1.9 failed unexpectedly: %v", err) + } +} + +func testLang(t *testing.T, lang, src, outfile string) error { + run := []string{testenv.GoToolPath(t), "tool", "compile", "-lang", lang, "-o", outfile, src} + t.Log(run) + out, err := exec.Command(run[0], run[1:]...).CombinedOutput() + t.Logf("%s", out) + return err +} diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 339e8e08cda17..059bf5d1fceec 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -19,11 +19,13 @@ import ( "cmd/internal/sys" "flag" "fmt" + "go/build" "io" "io/ioutil" "log" "os" "path" + "regexp" "runtime" "strconv" "strings" @@ -211,6 +213,7 @@ func Main(archInit func(*Arch)) { flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`") objabi.Flagcount("j", "debug runtime-initialized variables", &Debug['j']) objabi.Flagcount("l", "disable inlining", &Debug['l']) + flag.StringVar(&flag_lang, "lang", defaultLang(), "release to compile for") flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`") objabi.Flagcount("live", "debug liveness analysis", &debuglive) objabi.Flagcount("m", "print optimization decisions", &Debug['m']) @@ -277,6 +280,8 @@ func Main(archInit func(*Arch)) { Exit(2) } + checkLang() + thearch.LinkArch.Init(Ctxt) if outfile == "" { @@ -1304,3 +1309,66 @@ func recordFlags(flags ...string) { Ctxt.Data = append(Ctxt.Data, s) s.P = cmd.Bytes()[1:] } + +// flag_lang is the language version we are compiling for, set by the -lang flag. +var flag_lang string + +// defaultLang returns the default value for the -lang flag. +func defaultLang() string { + tags := build.Default.ReleaseTags + return tags[len(tags)-1] +} + +// goVersionRE is a regular expression that matches the valid +// arguments to the -lang flag. +var goVersionRE = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`) + +// A lang is a language version broken into major and minor numbers. +type lang struct { + major, minor int +} + +// langWant is the desired language version set by the -lang flag. +var langWant lang + +// langSupported reports whether language version major.minor is supported. +func langSupported(major, minor int) bool { + return langWant.major > major || (langWant.major == major && langWant.minor >= minor) +} + +// checkLang verifies that the -lang flag holds a valid value, and +// exits if not. It initializes data used by langSupported. +func checkLang() { + var err error + langWant, err = parseLang(flag_lang) + if err != nil { + log.Fatalf("invalid value %q for -lang: %v", flag_lang, err) + } + + if def := defaultLang(); flag_lang != def { + defVers, err := parseLang(def) + if err != nil { + log.Fatalf("internal error parsing default lang %q: %v", def, err) + } + if langWant.major > defVers.major || (langWant.major == defVers.major && langWant.major > defVers.minor) { + log.Fatalf("invalid value %q for -lang: max known version is %q", flag_lang, def) + } + } +} + +// parseLang parses a -lang option into a langVer. +func parseLang(s string) (lang, error) { + matches := goVersionRE.FindStringSubmatch(s) + if matches == nil { + return lang{}, fmt.Errorf(`should be something like "go1.12"`) + } + major, err := strconv.Atoi(matches[1]) + if err != nil { + return lang{}, err + } + minor, err := strconv.Atoi(matches[2]) + if err != nil { + return lang{}, err + } + return lang{major: major, minor: minor}, nil +} diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go index ca65c7ccca03f..8964536ff05d8 100644 --- a/src/cmd/compile/internal/gc/noder.go +++ b/src/cmd/compile/internal/gc/noder.go @@ -417,8 +417,11 @@ func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node { param.Pragma = 0 } - return p.nod(decl, ODCLTYPE, n, nil) - + nod := p.nod(decl, ODCLTYPE, n, nil) + if param.Alias && !langSupported(1, 9) { + yyerrorl(nod.Pos, "type aliases only supported as of -lang=go1.9") + } + return nod } func (p *noder) declNames(names []*syntax.Name) []*Node { diff --git a/src/cmd/compile/internal/gc/op_string.go b/src/cmd/compile/internal/gc/op_string.go index 8358854bf29aa..83283c72c6e7c 100644 --- a/src/cmd/compile/internal/gc/op_string.go +++ b/src/cmd/compile/internal/gc/op_string.go @@ -4,9 +4,9 @@ package gc import "strconv" -const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDARRAYBYTESTRARRAYBYTESTRTMPARRAYRUNESTRSTRARRAYBYTESTRARRAYBYTETMPSTRARRAYRUNEASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTINDINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTCOMPLUSMINUSORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELPROCRANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPRETJMPGETGEND" +const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDARRAYBYTESTRARRAYBYTESTRTMPARRAYRUNESTRSTRARRAYBYTESTRARRAYBYTETMPSTRARRAYRUNEASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTINDINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTCOMPLUSMINUSORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICEHEADERSLICE3SLICE3ARRRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELPROCRANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPRETJMPGETGEND" -var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 73, 88, 100, 112, 127, 139, 141, 144, 151, 158, 165, 175, 179, 183, 191, 199, 208, 216, 219, 224, 231, 238, 244, 253, 261, 269, 275, 279, 288, 295, 299, 302, 309, 317, 325, 332, 338, 341, 347, 354, 362, 366, 373, 381, 383, 385, 387, 389, 391, 393, 396, 401, 409, 412, 421, 424, 428, 436, 443, 452, 455, 458, 461, 464, 467, 470, 476, 479, 482, 485, 489, 494, 498, 503, 508, 514, 519, 523, 528, 536, 544, 550, 559, 566, 570, 577, 584, 592, 596, 600, 604, 611, 618, 626, 632, 637, 642, 646, 651, 659, 664, 669, 673, 676, 684, 688, 690, 695, 699, 704, 710, 716, 722, 728, 733, 737, 744, 750, 755, 761, 764, 770, 777, 782, 786, 791, 795, 805, 810, 818, 824, 831, 838, 846, 852, 856, 859} +var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 73, 88, 100, 112, 127, 139, 141, 144, 151, 158, 165, 175, 179, 183, 191, 199, 208, 216, 219, 224, 231, 238, 244, 253, 261, 269, 275, 279, 288, 295, 299, 302, 309, 317, 325, 332, 338, 341, 347, 354, 362, 366, 373, 381, 383, 385, 387, 389, 391, 393, 396, 401, 409, 412, 421, 424, 428, 436, 443, 452, 455, 458, 461, 464, 467, 470, 476, 479, 482, 485, 489, 494, 498, 503, 508, 514, 519, 523, 528, 536, 544, 555, 561, 570, 577, 581, 588, 595, 603, 607, 611, 615, 622, 629, 637, 643, 648, 653, 657, 662, 670, 675, 680, 684, 687, 695, 699, 701, 706, 710, 715, 721, 727, 733, 739, 744, 748, 755, 761, 766, 772, 775, 781, 788, 793, 797, 802, 806, 816, 821, 829, 835, 842, 849, 857, 863, 867, 870} func (i Op) String() string { if i >= Op(len(_Op_index)-1) { diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 549038e7d1445..4607cf1912661 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -2321,6 +2321,12 @@ func (s *state) expr(n *Node) *ssa.Value { data := s.expr(n.Right) return s.newValue2(ssa.OpIMake, n.Type, tab, data) + case OSLICEHEADER: + p := s.expr(n.Left) + l := s.expr(n.List.First()) + c := s.expr(n.List.Second()) + return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c) + case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR: v := s.expr(n.Left) var i, j, k *ssa.Value diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index 87b6d036c5e58..0fe6defe995d1 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -636,65 +636,66 @@ const ( ODCLCONST // const pi = 3.14 ODCLTYPE // type Int int or type Int = int - ODELETE // delete(Left, Right) - ODOT // Left.Sym (Left is of struct type) - ODOTPTR // Left.Sym (Left is of pointer to struct type) - ODOTMETH // Left.Sym (Left is non-interface, Right is method name) - ODOTINTER // Left.Sym (Left is interface, Right is method name) - OXDOT // Left.Sym (before rewrite to one of the preceding) - ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor - ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor - OEQ // Left == Right - ONE // Left != Right - OLT // Left < Right - OLE // Left <= Right - OGE // Left >= Right - OGT // Left > Right - OIND // *Left - OINDEX // Left[Right] (index of array or slice) - OINDEXMAP // Left[Right] (index of map) - OKEY // Left:Right (key:value in struct/array/map literal) - OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking) - OLEN // len(Left) - OMAKE // make(List) (before type checking converts to one of the following) - OMAKECHAN // make(Type, Left) (type is chan) - OMAKEMAP // make(Type, Left) (type is map) - OMAKESLICE // make(Type, Left, Right) (type is slice) - OMUL // Left * Right - ODIV // Left / Right - OMOD // Left % Right - OLSH // Left << Right - ORSH // Left >> Right - OAND // Left & Right - OANDNOT // Left &^ Right - ONEW // new(Left) - ONOT // !Left - OCOM // ^Left - OPLUS // +Left - OMINUS // -Left - OOROR // Left || Right - OPANIC // panic(Left) - OPRINT // print(List) - OPRINTN // println(List) - OPAREN // (Left) - OSEND // Left <- Right - OSLICE // Left[List[0] : List[1]] (Left is untypechecked or slice) - OSLICEARR // Left[List[0] : List[1]] (Left is array) - OSLICESTR // Left[List[0] : List[1]] (Left is string) - OSLICE3 // Left[List[0] : List[1] : List[2]] (Left is untypedchecked or slice) - OSLICE3ARR // Left[List[0] : List[1] : List[2]] (Left is array) - ORECOVER // recover() - ORECV // <-Left - ORUNESTR // Type(Left) (Type is string, Left is rune) - OSELRECV // Left = <-Right.Left: (appears as .Left of OCASE; Right.Op == ORECV) - OSELRECV2 // List = <-Right.Left: (apperas as .Left of OCASE; count(List) == 2, Right.Op == ORECV) - OIOTA // iota - OREAL // real(Left) - OIMAG // imag(Left) - OCOMPLEX // complex(Left, Right) - OALIGNOF // unsafe.Alignof(Left) - OOFFSETOF // unsafe.Offsetof(Left) - OSIZEOF // unsafe.Sizeof(Left) + ODELETE // delete(Left, Right) + ODOT // Left.Sym (Left is of struct type) + ODOTPTR // Left.Sym (Left is of pointer to struct type) + ODOTMETH // Left.Sym (Left is non-interface, Right is method name) + ODOTINTER // Left.Sym (Left is interface, Right is method name) + OXDOT // Left.Sym (before rewrite to one of the preceding) + ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor + ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor + OEQ // Left == Right + ONE // Left != Right + OLT // Left < Right + OLE // Left <= Right + OGE // Left >= Right + OGT // Left > Right + OIND // *Left + OINDEX // Left[Right] (index of array or slice) + OINDEXMAP // Left[Right] (index of map) + OKEY // Left:Right (key:value in struct/array/map literal) + OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking) + OLEN // len(Left) + OMAKE // make(List) (before type checking converts to one of the following) + OMAKECHAN // make(Type, Left) (type is chan) + OMAKEMAP // make(Type, Left) (type is map) + OMAKESLICE // make(Type, Left, Right) (type is slice) + OMUL // Left * Right + ODIV // Left / Right + OMOD // Left % Right + OLSH // Left << Right + ORSH // Left >> Right + OAND // Left & Right + OANDNOT // Left &^ Right + ONEW // new(Left) + ONOT // !Left + OCOM // ^Left + OPLUS // +Left + OMINUS // -Left + OOROR // Left || Right + OPANIC // panic(Left) + OPRINT // print(List) + OPRINTN // println(List) + OPAREN // (Left) + OSEND // Left <- Right + OSLICE // Left[List[0] : List[1]] (Left is untypechecked or slice) + OSLICEARR // Left[List[0] : List[1]] (Left is array) + OSLICESTR // Left[List[0] : List[1]] (Left is string) + OSLICE3 // Left[List[0] : List[1] : List[2]] (Left is untypedchecked or slice) + OSLICE3ARR // Left[List[0] : List[1] : List[2]] (Left is array) + OSLICEHEADER // sliceheader{Left, List[0], List[1]} (Left is unsafe.Pointer, List[0] is length, List[1] is capacity) + ORECOVER // recover() + ORECV // <-Left + ORUNESTR // Type(Left) (Type is string, Left is rune) + OSELRECV // Left = <-Right.Left: (appears as .Left of OCASE; Right.Op == ORECV) + OSELRECV2 // List = <-Right.Left: (apperas as .Left of OCASE; count(List) == 2, Right.Op == ORECV) + OIOTA // iota + OREAL // real(Left) + OIMAG // imag(Left) + OCOMPLEX // complex(Left, Right) + OALIGNOF // unsafe.Alignof(Left) + OOFFSETOF // unsafe.Offsetof(Left) + OSIZEOF // unsafe.Sizeof(Left) // statements OBLOCK // { List } (block of code) diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index cf26d84521904..6ee52eae843c8 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -1086,6 +1086,47 @@ func typecheck1(n *Node, top int) *Node { n.Right = assignconv(r, t.Elem(), "send") n.Type = nil + case OSLICEHEADER: + // Errors here are Fatalf instead of yyerror because only the compiler + // can construct an OSLICEHEADER node. + // Components used in OSLICEHEADER that are supplied by parsed source code + // have already been typechecked in e.g. OMAKESLICE earlier. + ok |= Erv + + t := n.Type + if !t.IsSlice() { + Fatalf("invalid type %v for OSLICEHEADER", n.Type) + } + + if !n.Left.Type.IsUnsafePtr() { + Fatalf("need unsafe.Pointer for OSLICEHEADER") + } + + if x := n.List.Len(); x != 2 { + Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x) + } + + n.Left = typecheck(n.Left, Erv) + l := typecheck(n.List.First(), Erv) + c := typecheck(n.List.Second(), Erv) + l = defaultlit(l, types.Types[TINT]) + c = defaultlit(c, types.Types[TINT]) + + if Isconst(l, CTINT) && l.Int64() < 0 { + Fatalf("len for OSLICEHEADER must be non-negative") + } + + if Isconst(c, CTINT) && c.Int64() < 0 { + Fatalf("cap for OSLICEHEADER must be non-negative") + } + + if Isconst(l, CTINT) && Isconst(c, CTINT) && l.Val().U.(*Mpint).Cmp(c.Val().U.(*Mpint)) > 0 { + Fatalf("len larger than cap for OSLICEHEADER") + } + + n.List.SetFirst(l) + n.List.SetSecond(c) + case OSLICE, OSLICE3: ok |= Erv n.Left = typecheck(n.Left, Erv) diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 6c1110a2945dd..c0fb5bfd28cb1 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -1118,6 +1118,11 @@ opswitch: case ORECV: Fatalf("walkexpr ORECV") // should see inside OAS only + case OSLICEHEADER: + n.Left = walkexpr(n.Left, init) + n.List.SetFirst(walkexpr(n.List.First(), init)) + n.List.SetSecond(walkexpr(n.List.Second(), init)) + case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: n.Left = walkexpr(n.Left, init) low, high, max := n.SliceBounds() @@ -1339,8 +1344,13 @@ opswitch: } fn := syslook(fnname) - fn = substArgTypes(fn, t.Elem()) // any-1 - n = mkcall1(fn, t, init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype)) + n.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype)) + n.Left.SetNonNil(true) + n.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT])) + n.Op = OSLICEHEADER + n.Type = t + n = typecheck(n, Erv) + n = walkexpr(n, init) } case ORUNESTR: diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 73d7663ad6ff2..f419d3c63a062 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -7,6 +7,7 @@ package main_test import ( "bytes" "cmd/internal/sys" + "context" "debug/elf" "debug/macho" "flag" @@ -108,6 +109,12 @@ var testGo string var testTmpDir string var testBin string +// testCtx is canceled when the test binary is about to time out. +// +// If https://golang.org/issue/28135 is accepted, uses of this variable in test +// functions should be replaced by t.Context(). +var testCtx = context.Background() + // The TestMain function creates a go command for testing purposes and // deletes it after the tests have been run. func TestMain(m *testing.M) { @@ -120,6 +127,20 @@ func TestMain(m *testing.M) { os.Unsetenv("GOROOT_FINAL") flag.Parse() + + timeoutFlag := flag.Lookup("test.timeout") + if timeoutFlag != nil { + // TODO(golang.org/issue/28147): The go command does not pass the + // test.timeout flag unless either -timeout or -test.timeout is explicitly + // set on the command line. + if d := timeoutFlag.Value.(flag.Getter).Get().(time.Duration); d != 0 { + aBitShorter := d * 95 / 100 + var cancel context.CancelFunc + testCtx, cancel = context.WithTimeout(testCtx, aBitShorter) + defer cancel() + } + } + if *proxyAddr != "" { StartProxy() select {} diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go index 8708dacd41ec9..f03d9840ca971 100644 --- a/src/cmd/go/script_test.go +++ b/src/cmd/go/script_test.go @@ -9,6 +9,7 @@ package main_test import ( "bytes" + "context" "fmt" "internal/testenv" "io/ioutil" @@ -55,21 +56,28 @@ func TestScript(t *testing.T) { // A testScript holds execution state for a single test script. type testScript struct { - t *testing.T - workdir string // temporary work dir ($WORK) - log bytes.Buffer // test execution log (printed at end of test) - mark int // offset of next log truncation - cd string // current directory during test execution; initially $WORK/gopath/src - name string // short name of test ("foo") - file string // full file name ("testdata/script/foo.txt") - lineno int // line number currently executing - line string // line currently executing - env []string // environment list (for os/exec) - envMap map[string]string // environment mapping (matches env) - stdout string // standard output from last 'go' command; for 'stdout' command - stderr string // standard error from last 'go' command; for 'stderr' command - stopped bool // test wants to stop early - start time.Time // time phase started + t *testing.T + workdir string // temporary work dir ($WORK) + log bytes.Buffer // test execution log (printed at end of test) + mark int // offset of next log truncation + cd string // current directory during test execution; initially $WORK/gopath/src + name string // short name of test ("foo") + file string // full file name ("testdata/script/foo.txt") + lineno int // line number currently executing + line string // line currently executing + env []string // environment list (for os/exec) + envMap map[string]string // environment mapping (matches env) + stdout string // standard output from last 'go' command; for 'stdout' command + stderr string // standard error from last 'go' command; for 'stderr' command + stopped bool // test wants to stop early + start time.Time // time phase started + background []backgroundCmd // backgrounded 'exec' and 'go' commands +} + +type backgroundCmd struct { + cmd *exec.Cmd + wait <-chan struct{} + neg bool // if true, cmd should fail } var extraEnvKeys = []string{ @@ -146,6 +154,17 @@ func (ts *testScript) run() { } defer func() { + // On a normal exit from the test loop, background processes are cleaned up + // before we print PASS. If we return early (e.g., due to a test failure), + // don't print anything about the processes that were still running. + for _, bg := range ts.background { + interruptProcess(bg.cmd.Process) + } + for _, bg := range ts.background { + <-bg.wait + } + ts.background = nil + markTime() // Flush testScript log to testing.T log. ts.t.Log("\n" + ts.abbrev(ts.log.String())) @@ -284,14 +303,23 @@ Script: // Command can ask script to stop early. if ts.stopped { - return + // Break instead of returning, so that we check the status of any + // background processes and print PASS. + break } } + for _, bg := range ts.background { + interruptProcess(bg.cmd.Process) + } + ts.cmdWait(false, nil) + // Final phase ended. rewind() markTime() - fmt.Fprintf(&ts.log, "PASS\n") + if !ts.stopped { + fmt.Fprintf(&ts.log, "PASS\n") + } } // scriptCmds are the script command implementations. @@ -317,6 +345,7 @@ var scriptCmds = map[string]func(*testScript, bool, []string){ "stdout": (*testScript).cmdStdout, "stop": (*testScript).cmdStop, "symlink": (*testScript).cmdSymlink, + "wait": (*testScript).cmdWait, } // addcrlf adds CRLF line endings to the named files. @@ -451,26 +480,43 @@ func (ts *testScript) cmdEnv(neg bool, args []string) { // exec runs the given command. func (ts *testScript) cmdExec(neg bool, args []string) { - if len(args) < 1 { - ts.fatalf("usage: exec program [args...]") + if len(args) < 1 || (len(args) == 1 && args[0] == "&") { + ts.fatalf("usage: exec program [args...] [&]") } + var err error - ts.stdout, ts.stderr, err = ts.exec(args[0], args[1:]...) - if ts.stdout != "" { - fmt.Fprintf(&ts.log, "[stdout]\n%s", ts.stdout) - } - if ts.stderr != "" { - fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr) + if len(args) > 0 && args[len(args)-1] == "&" { + var cmd *exec.Cmd + cmd, err = ts.execBackground(args[0], args[1:len(args)-1]...) + if err == nil { + wait := make(chan struct{}) + go func() { + ctxWait(testCtx, cmd) + close(wait) + }() + ts.background = append(ts.background, backgroundCmd{cmd, wait, neg}) + } + ts.stdout, ts.stderr = "", "" + } else { + ts.stdout, ts.stderr, err = ts.exec(args[0], args[1:]...) + if ts.stdout != "" { + fmt.Fprintf(&ts.log, "[stdout]\n%s", ts.stdout) + } + if ts.stderr != "" { + fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr) + } + if err == nil && neg { + ts.fatalf("unexpected command success") + } } + if err != nil { fmt.Fprintf(&ts.log, "[%v]\n", err) - if !neg { + if testCtx.Err() != nil { + ts.fatalf("test timed out while running command") + } else if !neg { ts.fatalf("unexpected command failure") } - } else { - if neg { - ts.fatalf("unexpected command success") - } } } @@ -545,6 +591,14 @@ func (ts *testScript) cmdSkip(neg bool, args []string) { if neg { ts.fatalf("unsupported: ! skip") } + + // Before we mark the test as skipped, shut down any background processes and + // make sure they have returned the correct status. + for _, bg := range ts.background { + interruptProcess(bg.cmd.Process) + } + ts.cmdWait(false, nil) + if len(args) == 1 { ts.t.Skip(args[0]) } @@ -687,6 +741,52 @@ func (ts *testScript) cmdSymlink(neg bool, args []string) { ts.check(os.Symlink(args[2], ts.mkabs(args[0]))) } +// wait waits for background commands to exit, setting stderr and stdout to their result. +func (ts *testScript) cmdWait(neg bool, args []string) { + if neg { + ts.fatalf("unsupported: ! wait") + } + if len(args) > 0 { + ts.fatalf("usage: wait") + } + + var stdouts, stderrs []string + for _, bg := range ts.background { + <-bg.wait + + args := append([]string{filepath.Base(bg.cmd.Args[0])}, bg.cmd.Args[1:]...) + fmt.Fprintf(&ts.log, "[background] %s: %v\n", strings.Join(args, " "), bg.cmd.ProcessState) + + cmdStdout := bg.cmd.Stdout.(*strings.Builder).String() + if cmdStdout != "" { + fmt.Fprintf(&ts.log, "[stdout]\n%s", cmdStdout) + stdouts = append(stdouts, cmdStdout) + } + + cmdStderr := bg.cmd.Stderr.(*strings.Builder).String() + if cmdStderr != "" { + fmt.Fprintf(&ts.log, "[stderr]\n%s", cmdStderr) + stderrs = append(stderrs, cmdStderr) + } + + if bg.cmd.ProcessState.Success() { + if bg.neg { + ts.fatalf("unexpected command success") + } + } else { + if testCtx.Err() != nil { + ts.fatalf("test timed out while running command") + } else if !bg.neg { + ts.fatalf("unexpected command failure") + } + } + } + + ts.stdout = strings.Join(stdouts, "") + ts.stderr = strings.Join(stderrs, "") + ts.background = nil +} + // Helpers for command implementations. // abbrev abbreviates the actual work directory in the string s to the literal string "$WORK". @@ -716,10 +816,51 @@ func (ts *testScript) exec(command string, args ...string) (stdout, stderr strin var stdoutBuf, stderrBuf strings.Builder cmd.Stdout = &stdoutBuf cmd.Stderr = &stderrBuf - err = cmd.Run() + if err = cmd.Start(); err == nil { + err = ctxWait(testCtx, cmd) + } return stdoutBuf.String(), stderrBuf.String(), err } +// execBackground starts the given command line (an actual subprocess, not simulated) +// in ts.cd with environment ts.env. +func (ts *testScript) execBackground(command string, args ...string) (*exec.Cmd, error) { + cmd := exec.Command(command, args...) + cmd.Dir = ts.cd + cmd.Env = append(ts.env, "PWD="+ts.cd) + var stdoutBuf, stderrBuf strings.Builder + cmd.Stdout = &stdoutBuf + cmd.Stderr = &stderrBuf + return cmd, cmd.Start() +} + +// ctxWait is like cmd.Wait, but terminates cmd with os.Interrupt if ctx becomes done. +// +// This differs from exec.CommandContext in that it prefers os.Interrupt over os.Kill. +// (See https://golang.org/issue/21135.) +func ctxWait(ctx context.Context, cmd *exec.Cmd) error { + errc := make(chan error, 1) + go func() { errc <- cmd.Wait() }() + + select { + case err := <-errc: + return err + case <-ctx.Done(): + interruptProcess(cmd.Process) + return <-errc + } +} + +// interruptProcess sends os.Interrupt to p if supported, or os.Kill otherwise. +func interruptProcess(p *os.Process) { + if err := p.Signal(os.Interrupt); err != nil { + // Per https://golang.org/pkg/os/#Signal, “Interrupt is not implemented on + // Windows; using it with os.Process.Signal will return an error.” + // Fall back to Kill instead. + p.Kill() + } +} + // expand applies environment variable expansion to the string s. func (ts *testScript) expand(s string) string { return os.Expand(s, func(key string) string { return ts.envMap[key] }) diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README index a80233b8c3830..f28f1b87ed323 100644 --- a/src/cmd/go/testdata/script/README +++ b/src/cmd/go/testdata/script/README @@ -99,16 +99,23 @@ The commands are: With no arguments, print the environment (useful for debugging). Otherwise add the listed key=value pairs to the environment. -- [!] exec program [args...] +- [!] exec program [args...] [&] Run the given executable program with the arguments. It must (or must not) succeed. Note that 'exec' does not terminate the script (unlike in Unix shells). + If the last token is '&', the program executes in the background. The standard + output and standard error of the previous command is cleared, but the output + of the background process is buffered — and checking of its exit status is + delayed — until the next call to 'wait', 'skip', or 'stop' or the end of the + test. At the end of the test, any remaining background processes are + terminated using os.Interrupt (if supported) or os.Kill. + - [!] exists [-readonly] file... Each of the listed files or directories must (or must not) exist. If -readonly is given, the files or directories must be unwritable. -- [!] go args... +- [!] go args... [&] Run the (test copy of the) go command with the given arguments. It must (or must not) succeed. @@ -131,11 +138,11 @@ The commands are: - [!] stderr [-count=N] pattern Apply the grep command (see above) to the standard error - from the most recent exec or go command. + from the most recent exec, go, or wait command. - [!] stdout [-count=N] pattern Apply the grep command (see above) to the standard output - from the most recent exec or go command. + from the most recent exec, go, or wait command. - stop [message] Stop the test early (marking it as passing), including the message if given. @@ -143,6 +150,13 @@ The commands are: - symlink file -> target Create file as a symlink to target. The -> (like in ls -l output) is required. +- wait + Wait for all 'exec' and 'go' commands started in the background (with the '&' + token) to exit, and display success or failure status for them. + After a call to wait, the 'stderr' and 'stdout' commands will apply to the + concatenation of the corresponding streams of the background commands, + in the order in which those commands were started. + When TestScript runs a script and the script fails, by default TestScript shows the execution of the most recent phase of the script (since the last # comment) and only shows the # comments for earlier phases. For example, here is a diff --git a/src/cmd/go/testdata/script/script_wait.txt b/src/cmd/go/testdata/script/script_wait.txt new file mode 100644 index 0000000000000..0770b39523d5f --- /dev/null +++ b/src/cmd/go/testdata/script/script_wait.txt @@ -0,0 +1,22 @@ +[!exec:echo] skip +[!exec:false] skip + +exec echo foo +stdout foo + +exec echo foo & +exec echo bar & +! exec false & + +# Starting a background process should clear previous output. +! stdout foo + +# Wait should set the output to the concatenated outputs of the background +# programs, in the order in which they were started. +wait +stdout 'foo\nbar' + +# The end of the test should interrupt or kill any remaining background +# programs. +[!exec:sleep] skip +! exec sleep 86400 & diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go index 51932882c0138..8fd429431595e 100644 --- a/src/crypto/tls/tls.go +++ b/src/crypto/tls/tls.go @@ -11,7 +11,6 @@ package tls // https://www.imperialviolet.org/2013/02/04/luckythirteen.html. import ( - "bytes" "crypto" "crypto/ecdsa" "crypto/rsa" @@ -30,10 +29,7 @@ import ( // The configuration config must be non-nil and must include // at least one certificate or else set GetCertificate. func Server(conn net.Conn, config *Config) *Conn { - return &Conn{ - conn: conn, config: config, - input: *bytes.NewReader(nil), // Issue 28269 - } + return &Conn{conn: conn, config: config} } // Client returns a new TLS client side connection @@ -41,10 +37,7 @@ func Server(conn net.Conn, config *Config) *Conn { // The config cannot be nil: users must set either ServerName or // InsecureSkipVerify in the config. func Client(conn net.Conn, config *Config) *Conn { - return &Conn{ - conn: conn, config: config, isClient: true, - input: *bytes.NewReader(nil), // Issue 28269 - } + return &Conn{conn: conn, config: config, isClient: true} } // A listener implements a network listener (net.Listener) for TLS connections. diff --git a/src/go/build/build.go b/src/go/build/build.go index fc8d37789f8ee..015551d008522 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -45,6 +45,7 @@ type Context struct { // which defaults to the list of Go releases the current release is compatible with. // In addition to the BuildTags and ReleaseTags, build constraints // consider the values of GOARCH and GOOS as satisfied tags. + // The last element in ReleaseTags is assumed to be the current release. BuildTags []string ReleaseTags []string @@ -296,6 +297,7 @@ func defaultContext() Context { // say "+build go1.x", and code that should only be built before Go 1.x // (perhaps it is the stub to use in that case) should say "+build !go1.x". // NOTE: If you add to this list, also update the doc comment in doc.go. + // NOTE: The last element in ReleaseTags should be the current release. const version = 11 // go1.11 for i := 1; i <= version; i++ { c.ReleaseTags = append(c.ReleaseTags, "go1."+strconv.Itoa(i)) diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go index 5e38ff7703b57..e210a6db9ec0b 100644 --- a/src/internal/cpu/cpu.go +++ b/src/internal/cpu/cpu.go @@ -47,27 +47,18 @@ type x86 struct { var PPC64 ppc64 -// For ppc64x, it is safe to check only for ISA level starting on ISA v3.00, +// For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00, // since there are no optional categories. There are some exceptions that also // require kernel support to work (darn, scv), so there are feature bits for -// those as well. The minimum processor requirement is POWER8 (ISA 2.07), so we -// maintain some of the old feature checks for optional categories for -// safety. +// those as well. The minimum processor requirement is POWER8 (ISA 2.07). // The struct is padded to avoid false sharing. type ppc64 struct { - _ CacheLinePad - HasVMX bool // Vector unit (Altivec) - HasDFP bool // Decimal Floating Point unit - HasVSX bool // Vector-scalar unit - HasHTM bool // Hardware Transactional Memory - HasISEL bool // Integer select - HasVCRYPTO bool // Vector cryptography - HasHTMNOSC bool // HTM: kernel-aborted transaction in syscalls - HasDARN bool // Hardware random number generator (requires kernel enablement) - HasSCV bool // Syscall vectored (requires kernel enablement) - IsPOWER8 bool // ISA v2.07 (POWER8) - IsPOWER9 bool // ISA v3.00 (POWER9) - _ CacheLinePad + _ CacheLinePad + HasDARN bool // Hardware random number generator (requires kernel enablement) + HasSCV bool // Syscall vectored (requires kernel enablement) + IsPOWER8 bool // ISA v2.07 (POWER8) + IsPOWER9 bool // ISA v3.00 (POWER9) + _ CacheLinePad } var ARM arm diff --git a/src/internal/cpu/cpu_ppc64x.go b/src/internal/cpu/cpu_ppc64x.go index 6bb83bb66715a..1e7959b30658b 100644 --- a/src/internal/cpu/cpu_ppc64x.go +++ b/src/internal/cpu/cpu_ppc64x.go @@ -21,44 +21,22 @@ const ( _PPC_FEATURE2_ARCH_3_00 = 0x00800000 // CPU features - _PPC_FEATURE_HAS_ALTIVEC = 0x10000000 - _PPC_FEATURE_HAS_DFP = 0x00000400 - _PPC_FEATURE_HAS_VSX = 0x00000080 - _PPC_FEATURE2_HAS_HTM = 0x40000000 - _PPC_FEATURE2_HAS_ISEL = 0x08000000 - _PPC_FEATURE2_HAS_VEC_CRYPTO = 0x02000000 - _PPC_FEATURE2_HTM_NOSC = 0x01000000 - _PPC_FEATURE2_DARN = 0x00200000 - _PPC_FEATURE2_SCV = 0x00100000 + _PPC_FEATURE2_DARN = 0x00200000 + _PPC_FEATURE2_SCV = 0x00100000 ) func doinit() { options = []option{ - {Name: "htm", Feature: &PPC64.HasHTM}, - {Name: "htmnosc", Feature: &PPC64.HasHTMNOSC}, {Name: "darn", Feature: &PPC64.HasDARN}, {Name: "scv", Feature: &PPC64.HasSCV}, + {Name: "power9", Feature: &PPC64.IsPOWER9}, // These capabilities should always be enabled on ppc64 and ppc64le: {Name: "power8", Feature: &PPC64.IsPOWER8, Required: true}, - {Name: "vmx", Feature: &PPC64.HasVMX, Required: true}, - {Name: "dfp", Feature: &PPC64.HasDFP, Required: true}, - {Name: "vsx", Feature: &PPC64.HasVSX, Required: true}, - {Name: "isel", Feature: &PPC64.HasISEL, Required: true}, - {Name: "vcrypto", Feature: &PPC64.HasVCRYPTO, Required: true}, } - // HWCAP feature bits - PPC64.HasVMX = isSet(HWCap, _PPC_FEATURE_HAS_ALTIVEC) - PPC64.HasDFP = isSet(HWCap, _PPC_FEATURE_HAS_DFP) - PPC64.HasVSX = isSet(HWCap, _PPC_FEATURE_HAS_VSX) - // HWCAP2 feature bits PPC64.IsPOWER8 = isSet(HWCap2, _PPC_FEATURE2_ARCH_2_07) - PPC64.HasHTM = isSet(HWCap2, _PPC_FEATURE2_HAS_HTM) - PPC64.HasISEL = isSet(HWCap2, _PPC_FEATURE2_HAS_ISEL) - PPC64.HasVCRYPTO = isSet(HWCap2, _PPC_FEATURE2_HAS_VEC_CRYPTO) - PPC64.HasHTMNOSC = isSet(HWCap2, _PPC_FEATURE2_HTM_NOSC) PPC64.IsPOWER9 = isSet(HWCap2, _PPC_FEATURE2_ARCH_3_00) PPC64.HasDARN = isSet(HWCap2, _PPC_FEATURE2_DARN) PPC64.HasSCV = isSet(HWCap2, _PPC_FEATURE2_SCV) diff --git a/src/math/big/float.go b/src/math/big/float.go index 6b0cb3f1edd7e..d5e801b2c8939 100644 --- a/src/math/big/float.go +++ b/src/math/big/float.go @@ -43,7 +43,7 @@ const debugFloat = false // enable for debugging // precision of the argument with the largest precision value before any // rounding takes place, and the rounding mode remains unchanged. Thus, // uninitialized Floats provided as result arguments will have their -// precision set to a reasonable value determined by the operands and +// precision set to a reasonable value determined by the operands, and // their mode is the zero value for RoundingMode (ToNearestEven). // // By setting the desired precision to 24 or 53 and using matching rounding @@ -56,6 +56,12 @@ const debugFloat = false // enable for debugging // The zero (uninitialized) value for a Float is ready to use and represents // the number +0.0 exactly, with precision 0 and rounding mode ToNearestEven. // +// Operations always take pointer arguments (*Float) rather +// than Float values, and each unique Float value requires +// its own unique *Float pointer. To "copy" a Float value, +// an existing (or newly allocated) Float must be set to +// a new value using the Float.Set method; shallow copies +// of Floats are not supported and may lead to errors. type Float struct { prec uint32 mode RoundingMode diff --git a/src/math/big/int.go b/src/math/big/int.go index 47a288ab44d87..dab9a5cc0f7e6 100644 --- a/src/math/big/int.go +++ b/src/math/big/int.go @@ -15,6 +15,13 @@ import ( // An Int represents a signed multi-precision integer. // The zero value for an Int represents the value 0. +// +// Operations always take pointer arguments (*Int) rather +// than Int values, and each unique Int value requires +// its own unique *Int pointer. To "copy" an Int value, +// an existing (or newly allocated) Int must be set to +// a new value using the Int.Set method; shallow copies +// of Ints are not supported and may lead to errors. type Int struct { neg bool // sign abs nat // absolute value of the integer diff --git a/src/math/big/rat.go b/src/math/big/rat.go index 46d58fcf365d2..5d0800ca936b2 100644 --- a/src/math/big/rat.go +++ b/src/math/big/rat.go @@ -13,6 +13,13 @@ import ( // A Rat represents a quotient a/b of arbitrary precision. // The zero value for a Rat represents the value 0. +// +// Operations always take pointer arguments (*Rat) rather +// than Rat values, and each unique Rat value requires +// its own unique *Rat pointer. To "copy" a Rat value, +// an existing (or newly allocated) Rat must be set to +// a new value using the Rat.Set method; shallow copies +// of Rats are not supported and may lead to errors. type Rat struct { // To make zero values for Rat work w/o initialization, // a zero value of b (len(b) == 0) acts like b == 1. diff --git a/src/net/http/request.go b/src/net/http/request.go index 3669f17f66cd3..0bcdeae0df1f5 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -53,8 +53,9 @@ var ( // available. ErrNotSupported = &ProtocolError{"feature not supported"} - // ErrUnexpectedTrailer is returned by the Transport when a server - // replies with a Trailer header, but without a chunked reply. + // Deprecated: ErrUnexpectedTrailer is no longer returned by + // anything in the net/http package. Callers should not + // compare errors against this variable. ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"} // ErrMissingBoundary is returned by Request.MultipartReader when the diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go index c28b0cba89e87..c46f13f798833 100644 --- a/src/net/http/response_test.go +++ b/src/net/http/response_test.go @@ -157,6 +157,34 @@ var respTests = []respTest{ "Body here\ncontinued", }, + // Trailer header but no TransferEncoding + { + "HTTP/1.0 200 OK\r\n" + + "Trailer: Content-MD5, Content-Sources\r\n" + + "Content-Length: 10\r\n" + + "Connection: close\r\n" + + "\r\n" + + "Body here\n", + + Response{ + Status: "200 OK", + StatusCode: 200, + Proto: "HTTP/1.0", + ProtoMajor: 1, + ProtoMinor: 0, + Request: dummyReq("GET"), + Header: Header{ + "Connection": {"close"}, + "Content-Length": {"10"}, + "Trailer": []string{"Content-MD5, Content-Sources"}, + }, + Close: true, + ContentLength: 10, + }, + + "Body here\n", + }, + // Chunked response with Content-Length. { "HTTP/1.1 200 OK\r\n" + diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go index f0b43844dd92c..3eb9f0da91298 100644 --- a/src/net/http/transfer.go +++ b/src/net/http/transfer.go @@ -740,6 +740,16 @@ func fixTrailer(header Header, te []string) (Header, error) { if !ok { return nil, nil } + if !chunked(te) { + // Trailer and no chunking: + // this is an invalid use case for trailer header. + // Nevertheless, no error will be returned and we + // let users decide if this is a valid HTTP message. + // The Trailer header will be kept in Response.Header + // but not populate Response.Trailer. + // See issue #27197. + return nil, nil + } header.Del("Trailer") trailer := make(Header) @@ -763,10 +773,6 @@ func fixTrailer(header Header, te []string) (Header, error) { if len(trailer) == 0 { return nil, nil } - if !chunked(te) { - // Trailer and no chunking - return nil, ErrUnexpectedTrailer - } return trailer, nil } diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index 0c24d3dce680e..ee63285ec5f0a 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -266,8 +266,11 @@ func testGdbPython(t *testing.T, cgo bool) { infoLocalsRe1 := regexp.MustCompile(`slicevar *= *\[\]string *= *{"def"}`) // Format output from gdb v8.2 infoLocalsRe2 := regexp.MustCompile(`^slicevar = .*\nmapvar = .*\nstrvar = 0x[0-9a-f]+ "abc"`) + // Format output from gdb v7.7 + infoLocalsRe3 := regexp.MustCompile(`^mapvar = .*\nstrvar = "abc"\nslicevar *= *\[\]string`) if bl := blocks["info locals"]; !infoLocalsRe1.MatchString(bl) && - !infoLocalsRe2.MatchString(bl) { + !infoLocalsRe2.MatchString(bl) && + !infoLocalsRe3.MatchString(bl) { t.Fatalf("info locals failed: %s", bl) } diff --git a/src/runtime/slice.go b/src/runtime/slice.go index 9a081043b0510..2309b1a615ee5 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -31,7 +31,7 @@ func panicmakeslicecap() { panic(errorString("makeslice: cap out of range")) } -func makeslice(et *_type, len, cap int) slice { +func makeslice(et *_type, len, cap int) unsafe.Pointer { mem, overflow := math.MulUintptr(et.size, uintptr(cap)) if overflow || mem > maxAlloc || len < 0 || len > cap { // NOTE: Produce a 'len out of range' error instead of a @@ -45,12 +45,11 @@ func makeslice(et *_type, len, cap int) slice { } panicmakeslicecap() } - p := mallocgc(mem, et, true) - return slice{p, len, cap} + return mallocgc(mem, et, true) } -func makeslice64(et *_type, len64, cap64 int64) slice { +func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer { len := int(len64) if int64(len) != len64 { panicmakeslicelen() diff --git a/src/strings/reader.go b/src/strings/reader.go index 6c1a5064c0d5e..eb2fa1164c0fc 100644 --- a/src/strings/reader.go +++ b/src/strings/reader.go @@ -13,6 +13,7 @@ import ( // A Reader implements the io.Reader, io.ReaderAt, io.Seeker, io.WriterTo, // io.ByteScanner, and io.RuneScanner interfaces by reading // from a string. +// The zero value for Reader operates like a Reader of an empty string. type Reader struct { s string i int64 // current reading index @@ -70,10 +71,10 @@ func (r *Reader) ReadByte() (byte, error) { } func (r *Reader) UnreadByte() error { - r.prevRune = -1 if r.i <= 0 { return errors.New("strings.Reader.UnreadByte: at beginning of string") } + r.prevRune = -1 r.i-- return nil } @@ -94,6 +95,9 @@ func (r *Reader) ReadRune() (ch rune, size int, err error) { } func (r *Reader) UnreadRune() error { + if r.i <= 0 { + return errors.New("strings.Reader.UnreadRune: at beginning of string") + } if r.prevRune < 0 { return errors.New("strings.Reader.UnreadRune: previous operation was not ReadRune") } diff --git a/src/strings/reader_test.go b/src/strings/reader_test.go index bf40eb1a31eb4..a4c211d699f97 100644 --- a/src/strings/reader_test.go +++ b/src/strings/reader_test.go @@ -190,3 +190,45 @@ func TestReaderReset(t *testing.T) { t.Errorf("ReadAll: got %q, want %q", got, want) } } + +func TestReaderZero(t *testing.T) { + if l := (&strings.Reader{}).Len(); l != 0 { + t.Errorf("Len: got %d, want 0", l) + } + + if n, err := (&strings.Reader{}).Read(nil); n != 0 || err != io.EOF { + t.Errorf("Read: got %d, %v; want 0, io.EOF", n, err) + } + + if n, err := (&strings.Reader{}).ReadAt(nil, 11); n != 0 || err != io.EOF { + t.Errorf("ReadAt: got %d, %v; want 0, io.EOF", n, err) + } + + if b, err := (&strings.Reader{}).ReadByte(); b != 0 || err != io.EOF { + t.Errorf("ReadByte: got %d, %v; want 0, io.EOF", b, err) + } + + if ch, size, err := (&strings.Reader{}).ReadRune(); ch != 0 || size != 0 || err != io.EOF { + t.Errorf("ReadRune: got %d, %d, %v; want 0, 0, io.EOF", ch, size, err) + } + + if offset, err := (&strings.Reader{}).Seek(11, io.SeekStart); offset != 11 || err != nil { + t.Errorf("Seek: got %d, %v; want 11, nil", offset, err) + } + + if s := (&strings.Reader{}).Size(); s != 0 { + t.Errorf("Size: got %d, want 0", s) + } + + if (&strings.Reader{}).UnreadByte() == nil { + t.Errorf("UnreadByte: got nil, want error") + } + + if (&strings.Reader{}).UnreadRune() == nil { + t.Errorf("UnreadRune: got nil, want error") + } + + if n, err := (&strings.Reader{}).WriteTo(ioutil.Discard); n != 0 || err != nil { + t.Errorf("WriteTo: got %d, %v; want 0, nil", n, err) + } +} diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go index c65fb0144ac16..ae80e31df46d7 100644 --- a/test/codegen/arithmetic.go +++ b/test/codegen/arithmetic.go @@ -34,6 +34,8 @@ func SubMem(arr []int, b, c, d int) int { arr[d] -= 15 // 386:`DECL\s\([A-Z]+\)\([A-Z]+\*4\)` arr[b]-- + // amd64:`DECQ\s64\([A-Z]+\)` + arr[8]-- // 386:"SUBL\t4" // amd64:"SUBQ\t8" return arr[0] - arr[1]