From bdb480fd623e58d0d1d0689a3755367379ea57bc Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 8 Sep 2020 15:28:43 +0700 Subject: cmd/compile: fix mishandling of unsafe-uintptr arguments in go/defer Currently, the statement: go g(uintptr(f())) gets rewritten into: tmp := f() newproc(8, g, uintptr(tmp)) runtime.KeepAlive(tmp) which doesn't guarantee that tmp is still alive by time the g call is scheduled to run. This CL fixes the issue, by wrapping g call in a closure: go func(p unsafe.Pointer) { g(uintptr(p)) }(f()) then this will be rewritten into: tmp := f() go func(p unsafe.Pointer) { g(uintptr(p)) runtime.KeepAlive(p) }(tmp) runtime.KeepAlive(tmp) // superfluous, but harmless So the unsafe.Pointer p will be kept alive at the time g call runs. Updates #24491 Change-Id: Ic10821251cbb1b0073daec92b82a866c6ebaf567 Reviewed-on: https://go-review.googlesource.com/c/go/+/253457 Run-TryBot: Cuong Manh Le Reviewed-by: Matthew Dempsky TryBot-Result: Gobot Gobot --- test/fixedbugs/issue24491.go | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 test/fixedbugs/issue24491.go (limited to 'test/fixedbugs') diff --git a/test/fixedbugs/issue24491.go b/test/fixedbugs/issue24491.go new file mode 100644 index 0000000000..4703368793 --- /dev/null +++ b/test/fixedbugs/issue24491.go @@ -0,0 +1,45 @@ +// run + +// Copyright 2020 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 test makes sure unsafe-uintptr arguments are handled correctly. + +package main + +import ( + "runtime" + "unsafe" +) + +var done = make(chan bool, 1) + +func setup() unsafe.Pointer { + s := "ok" + runtime.SetFinalizer(&s, func(p *string) { *p = "FAIL" }) + return unsafe.Pointer(&s) +} + +//go:noinline +//go:uintptrescapes +func test(s string, p uintptr) { + runtime.GC() + if *(*string)(unsafe.Pointer(p)) != "ok" { + panic(s + " return unexpected result") + } + done <- true +} + +func main() { + test("normal", uintptr(setup())) + <-done + + go test("go", uintptr(setup())) + <-done + + func() { + defer test("defer", uintptr(setup())) + }() + <-done +} -- cgit v1.3 From 2c95e3a6a8377ca9c72608c25b4cf2506baf782f Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 9 Sep 2020 11:09:01 +0700 Subject: cmd/compile: use clearer error message for stuct literal This CL changes "T literal.M" error message to "T{...}.M". It's clearer expression and focusing user on actual issue. Updates #38745 Change-Id: I84b455a86742f37e0bde5bf390aa02984eecc3c9 Reviewed-on: https://go-review.googlesource.com/c/go/+/253677 Run-TryBot: Cuong Manh Le TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/fmt.go | 11 ++- test/alias2.go | 10 +-- test/ddd1.go | 2 +- test/escape2.go | 56 ++++++------- test/escape2n.go | 56 ++++++------- test/escape_calls.go | 2 +- test/escape_field.go | 6 +- test/escape_iface.go | 50 ++++++------ test/escape_indir.go | 34 ++++---- test/escape_map.go | 26 +++--- test/escape_param.go | 60 +++++++------- test/escape_slice.go | 14 ++-- test/escape_struct_param1.go | 158 ++++++++++++++++++------------------- test/escape_struct_param2.go | 158 ++++++++++++++++++------------------- test/fixedbugs/issue12006.go | 4 +- test/fixedbugs/issue13799.go | 4 +- test/fixedbugs/issue17645.go | 2 +- test/fixedbugs/issue21709.go | 4 +- test/fixedbugs/issue23732.go | 6 +- test/fixedbugs/issue26855.go | 4 +- test/fixedbugs/issue30898.go | 2 +- test/fixedbugs/issue31573.go | 24 +++--- test/fixedbugs/issue38745.go | 19 +++++ test/fixedbugs/issue39292.go | 6 +- test/fixedbugs/issue41247.go | 2 +- test/fixedbugs/issue7921.go | 10 +-- test/inline_variadic.go | 2 +- 27 files changed, 379 insertions(+), 353 deletions(-) create mode 100644 test/fixedbugs/issue38745.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 866cd0a714..43e501deaf 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -1407,7 +1407,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) { return } if n.Right != nil { - mode.Fprintf(s, "%v literal", n.Right) + mode.Fprintf(s, "%v{%s}", n.Right, ellipsisIf(n.List.Len() != 0)) return } @@ -1421,7 +1421,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) { case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT: if mode == FErr { - mode.Fprintf(s, "%v literal", n.Type) + mode.Fprintf(s, "%v{%s}", n.Type, ellipsisIf(n.List.Len() != 0)) return } mode.Fprintf(s, "(%v{ %.v })", n.Type, n.List) @@ -1934,3 +1934,10 @@ func indent(s fmt.State) { fmt.Fprint(s, ". ") } } + +func ellipsisIf(b bool) string { + if b { + return "..." + } + return "" +} diff --git a/test/alias2.go b/test/alias2.go index 7ea1b2908d..1c141ac490 100644 --- a/test/alias2.go +++ b/test/alias2.go @@ -46,8 +46,8 @@ var _ A0 = T0{} var _ T0 = A0{} // But aliases and original types cannot be used with new types based on them. -var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type" -var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type" +var _ N0 = T0{} // ERROR "cannot use T0{} \(type T0\) as type N0 in assignment|incompatible type" +var _ N0 = A0{} // ERROR "cannot use T0{} \(type T0\) as type N0 in assignment|incompatible type" var _ A5 = Value{} @@ -82,10 +82,10 @@ func _() { var _ A0 = T0{} var _ T0 = A0{} - var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type" - var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type" + var _ N0 = T0{} // ERROR "cannot use T0{} \(type T0\) as type N0 in assignment|incompatible type" + var _ N0 = A0{} // ERROR "cannot use T0{} \(type T0\) as type N0 in assignment|incompatible type" - var _ A5 = Value{} // ERROR "cannot use reflect\.Value literal \(type reflect.Value\) as type A5 in assignment|incompatible type" + var _ A5 = Value{} // ERROR "cannot use reflect\.Value{} \(type reflect.Value\) as type A5 in assignment|incompatible type" } // Invalid type alias declarations. diff --git a/test/ddd1.go b/test/ddd1.go index b582f221b7..2c7e83e374 100644 --- a/test/ddd1.go +++ b/test/ddd1.go @@ -19,7 +19,7 @@ var ( _ = sum(1.0, 2.0) _ = sum(1.5) // ERROR "integer" _ = sum("hello") // ERROR ".hello. .type untyped string. as type int|incompatible" - _ = sum([]int{1}) // ERROR "\[\]int literal.*as type int|incompatible" + _ = sum([]int{1}) // ERROR "\[\]int{...}.*as type int|incompatible" ) func sum3(int, int, int) int { return 0 } diff --git a/test/escape2.go b/test/escape2.go index cf24f4bebc..5c6eb559fa 100644 --- a/test/escape2.go +++ b/test/escape2.go @@ -118,15 +118,15 @@ type Bar struct { } func NewBar() *Bar { - return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" + return &Bar{42, nil} // ERROR "&Bar{...} escapes to heap$" } func NewBarp(x *int) *Bar { // ERROR "leaking param: x$" - return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" + return &Bar{42, x} // ERROR "&Bar{...} escapes to heap$" } func NewBarp2(x *int) *Bar { // ERROR "x does not escape$" - return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$" + return &Bar{*x, nil} // ERROR "&Bar{...} escapes to heap$" } func (b *Bar) NoLeak() int { // ERROR "b does not escape$" @@ -173,7 +173,7 @@ type Bar2 struct { } func NewBar2() *Bar2 { - return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$" + return &Bar2{[12]int{42}, nil} // ERROR "&Bar2{...} escapes to heap$" } func (b *Bar2) NoLeak() int { // ERROR "b does not escape$" @@ -539,7 +539,7 @@ func foo72b() [10]*int { // issue 2145 func foo73() { - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for _, v := range s { vv := v // actually just escapes its scope @@ -550,7 +550,7 @@ func foo73() { } func foo731() { - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for _, v := range s { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope @@ -562,7 +562,7 @@ func foo731() { } func foo74() { - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for _, v := range s { vv := v // actually just escapes its scope @@ -574,7 +574,7 @@ func foo74() { } func foo74a() { - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for _, v := range s { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope @@ -589,7 +589,7 @@ func foo74a() { // issue 3975 func foo74b() { var array [3]func() - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for i, v := range s { vv := v // actually just escapes its scope @@ -601,7 +601,7 @@ func foo74b() { func foo74c() { var array [3]func() - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for i, v := range s { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope @@ -759,15 +759,15 @@ type LimitedFooer struct { } func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r$" - return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$" + return &LimitedFooer{r, n} // ERROR "&LimitedFooer{...} escapes to heap$" } func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$" - return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int{...} escapes to heap$" } func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$" - return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int{...} escapes to heap$" } func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" @@ -870,15 +870,15 @@ func foo106(x *int) { // ERROR "leaking param: x$" } func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$" - return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int{...} escapes to heap$" } func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$" - return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int{...} escapes to heap$" } func foo109(x *int) *int { // ERROR "leaking param: x$" - m := map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal does not escape$" + m := map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int{...} does not escape$" for k, _ := range m { return k } @@ -886,12 +886,12 @@ func foo109(x *int) *int { // ERROR "leaking param: x$" } func foo110(x *int) *int { // ERROR "leaking param: x$" - m := map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal does not escape$" + m := map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int{...} does not escape$" return m[nil] } func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" - m := []*int{x} // ERROR "\[\]\*int literal does not escape$" + m := []*int{x} // ERROR "\[\]\*int{...} does not escape$" return m[0] } @@ -906,7 +906,7 @@ func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" } func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - m := &Bar{ii: x} // ERROR "&Bar literal does not escape$" + m := &Bar{ii: x} // ERROR "&Bar{...} does not escape$" return m.ii } @@ -1343,8 +1343,8 @@ func foo140() interface{} { X string T *T } - t := &T{} // ERROR "&T literal escapes to heap$" - return U{ // ERROR "U literal escapes to heap$" + t := &T{} // ERROR "&T{} escapes to heap$" + return U{ // ERROR "U{...} escapes to heap$" X: t.X, T: t, } @@ -1530,7 +1530,7 @@ type V struct { } func NewV(u U) *V { // ERROR "leaking param: u$" - return &V{u.String()} // ERROR "&V literal escapes to heap$" + return &V{u.String()} // ERROR "&V{...} escapes to heap$" } func foo152() { @@ -1571,21 +1571,21 @@ type Lit struct { func ptrlitNoescape() { // Both literal and element do not escape. i := 0 - x := &Lit{&i} // ERROR "&Lit literal does not escape$" + x := &Lit{&i} // ERROR "&Lit{...} does not escape$" _ = x } func ptrlitNoEscape2() { // Literal does not escape, but element does. i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "&Lit literal does not escape$" + x := &Lit{&i} // ERROR "&Lit{...} does not escape$" sink = *x } func ptrlitEscape() { // Both literal and element escape. i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" + x := &Lit{&i} // ERROR "&Lit{...} escapes to heap$" sink = x } @@ -1760,18 +1760,18 @@ func stringtoslicerune2() { } func slicerunetostring0() { - r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune{...} does not escape$" s := string(r) // ERROR "string\(r\) does not escape$" _ = s } func slicerunetostring1() string { - r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune{...} does not escape$" return string(r) // ERROR "string\(r\) escapes to heap$" } func slicerunetostring2() { - r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune{...} does not escape$" sink = string(r) // ERROR "string\(r\) escapes to heap$" } diff --git a/test/escape2n.go b/test/escape2n.go index f771e0aef2..46e58f8566 100644 --- a/test/escape2n.go +++ b/test/escape2n.go @@ -118,15 +118,15 @@ type Bar struct { } func NewBar() *Bar { - return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" + return &Bar{42, nil} // ERROR "&Bar{...} escapes to heap$" } func NewBarp(x *int) *Bar { // ERROR "leaking param: x$" - return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" + return &Bar{42, x} // ERROR "&Bar{...} escapes to heap$" } func NewBarp2(x *int) *Bar { // ERROR "x does not escape$" - return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$" + return &Bar{*x, nil} // ERROR "&Bar{...} escapes to heap$" } func (b *Bar) NoLeak() int { // ERROR "b does not escape$" @@ -173,7 +173,7 @@ type Bar2 struct { } func NewBar2() *Bar2 { - return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$" + return &Bar2{[12]int{42}, nil} // ERROR "&Bar2{...} escapes to heap$" } func (b *Bar2) NoLeak() int { // ERROR "b does not escape$" @@ -539,7 +539,7 @@ func foo72b() [10]*int { // issue 2145 func foo73() { - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for _, v := range s { vv := v // actually just escapes its scope @@ -550,7 +550,7 @@ func foo73() { } func foo731() { - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for _, v := range s { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope @@ -562,7 +562,7 @@ func foo731() { } func foo74() { - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for _, v := range s { vv := v // actually just escapes its scope @@ -574,7 +574,7 @@ func foo74() { } func foo74a() { - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for _, v := range s { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope @@ -589,7 +589,7 @@ func foo74a() { // issue 3975 func foo74b() { var array [3]func() - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for i, v := range s { vv := v // actually just escapes its scope @@ -601,7 +601,7 @@ func foo74b() { func foo74c() { var array [3]func() - s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int{...} does not escape$" for i, v := range s { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope @@ -759,15 +759,15 @@ type LimitedFooer struct { } func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r$" - return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$" + return &LimitedFooer{r, n} // ERROR "&LimitedFooer{...} escapes to heap$" } func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$" - return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int{...} escapes to heap$" } func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$" - return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int{...} escapes to heap$" } func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" @@ -870,15 +870,15 @@ func foo106(x *int) { // ERROR "leaking param: x$" } func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$" - return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int{...} escapes to heap$" } func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$" - return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int{...} escapes to heap$" } func foo109(x *int) *int { // ERROR "leaking param: x$" - m := map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal does not escape$" + m := map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int{...} does not escape$" for k, _ := range m { return k } @@ -886,12 +886,12 @@ func foo109(x *int) *int { // ERROR "leaking param: x$" } func foo110(x *int) *int { // ERROR "leaking param: x$" - m := map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal does not escape$" + m := map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int{...} does not escape$" return m[nil] } func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" - m := []*int{x} // ERROR "\[\]\*int literal does not escape$" + m := []*int{x} // ERROR "\[\]\*int{...} does not escape$" return m[0] } @@ -906,7 +906,7 @@ func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" } func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - m := &Bar{ii: x} // ERROR "&Bar literal does not escape$" + m := &Bar{ii: x} // ERROR "&Bar{...} does not escape$" return m.ii } @@ -1343,8 +1343,8 @@ func foo140() interface{} { X string T *T } - t := &T{} // ERROR "&T literal escapes to heap$" - return U{ // ERROR "U literal escapes to heap$" + t := &T{} // ERROR "&T{} escapes to heap$" + return U{ // ERROR "U{...} escapes to heap$" X: t.X, T: t, } @@ -1530,7 +1530,7 @@ type V struct { } func NewV(u U) *V { // ERROR "leaking param: u$" - return &V{u.String()} // ERROR "&V literal escapes to heap$" + return &V{u.String()} // ERROR "&V{...} escapes to heap$" } func foo152() { @@ -1571,21 +1571,21 @@ type Lit struct { func ptrlitNoescape() { // Both literal and element do not escape. i := 0 - x := &Lit{&i} // ERROR "&Lit literal does not escape$" + x := &Lit{&i} // ERROR "&Lit{...} does not escape$" _ = x } func ptrlitNoEscape2() { // Literal does not escape, but element does. i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "&Lit literal does not escape$" + x := &Lit{&i} // ERROR "&Lit{...} does not escape$" sink = *x } func ptrlitEscape() { // Both literal and element escape. i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" + x := &Lit{&i} // ERROR "&Lit{...} escapes to heap$" sink = x } @@ -1760,18 +1760,18 @@ func stringtoslicerune2() { } func slicerunetostring0() { - r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune{...} does not escape$" s := string(r) // ERROR "string\(r\) does not escape$" _ = s } func slicerunetostring1() string { - r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune{...} does not escape$" return string(r) // ERROR "string\(r\) escapes to heap$" } func slicerunetostring2() { - r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune{...} does not escape$" sink = string(r) // ERROR "string\(r\) escapes to heap$" } diff --git a/test/escape_calls.go b/test/escape_calls.go index 2dbfee1558..9e1db5426e 100644 --- a/test/escape_calls.go +++ b/test/escape_calls.go @@ -50,5 +50,5 @@ func bar() { f := prototype f = func(ss []string) { got = append(got, ss) } // ERROR "leaking param: ss" "func literal does not escape" s := "string" - f([]string{s}) // ERROR "\[\]string literal escapes to heap" + f([]string{s}) // ERROR "\[\]string{...} escapes to heap" } diff --git a/test/escape_field.go b/test/escape_field.go index bf1dfb18ff..95d0784d91 100644 --- a/test/escape_field.go +++ b/test/escape_field.go @@ -127,20 +127,20 @@ func field12() { func field13() { i := 0 // ERROR "moved to heap: i$" - x := &X{p1: &i} // ERROR "&X literal does not escape$" + x := &X{p1: &i} // ERROR "&X{...} does not escape$" sink = x.p1 } func field14() { i := 0 // ERROR "moved to heap: i$" // BAD: &i should not escape - x := &X{p1: &i} // ERROR "&X literal does not escape$" + x := &X{p1: &i} // ERROR "&X{...} does not escape$" sink = x.p2 } func field15() { i := 0 // ERROR "moved to heap: i$" - x := &X{p1: &i} // ERROR "&X literal escapes to heap$" + x := &X{p1: &i} // ERROR "&X{...} escapes to heap$" sink = x } diff --git a/test/escape_iface.go b/test/escape_iface.go index 118ed3c56f..7b0914cadb 100644 --- a/test/escape_iface.go +++ b/test/escape_iface.go @@ -37,7 +37,7 @@ func efaceEscape0() { _ = x } { - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" v := M0{&i} var x M = v sink = x @@ -50,7 +50,7 @@ func efaceEscape0() { _ = v1 } { - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" v := M0{&i} // BAD: v does not escape to heap here var x M = v @@ -58,14 +58,14 @@ func efaceEscape0() { sink = v1 } { - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" v := M0{&i} // BAD: v does not escape to heap here var x M = v x.M() } { - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" v := M0{&i} var x M = v mescapes(x) @@ -91,46 +91,46 @@ func efaceEscape1() { { i := 0 v := M1{&i, 0} - var x M = v // ERROR "v does not escape" + var x M = v // ERROR "v does not escape" _ = x } { - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" v := M1{&i, 0} - var x M = v // ERROR "v escapes to heap" + var x M = v // ERROR "v escapes to heap" sink = x } { i := 0 v := M1{&i, 0} - var x M = v // ERROR "v does not escape" + var x M = v // ERROR "v does not escape" v1 := x.(M1) _ = v1 } { - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" v := M1{&i, 0} var x M = v // ERROR "v does not escape" v1 := x.(M1) sink = v1 // ERROR "v1 escapes to heap" } { - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" v := M1{&i, 0} // BAD: v does not escape to heap here var x M = v // ERROR "v escapes to heap" x.M() } { - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" v := M1{&i, 0} - var x M = v // ERROR "v escapes to heap" + var x M = v // ERROR "v escapes to heap" mescapes(x) } { i := 0 v := M1{&i, 0} - var x M = v // ERROR "v does not escape" + var x M = v // ERROR "v does not escape" mdoesnotescape(x) } } @@ -146,26 +146,26 @@ func (*M2) M() { func efaceEscape2() { { i := 0 - v := &M2{&i} // ERROR "&M2 literal does not escape" + v := &M2{&i} // ERROR "&M2{...} does not escape" var x M = v _ = x } { i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&M2 literal escapes to heap" + v := &M2{&i} // ERROR "&M2{...} escapes to heap" var x M = v sink = x } { i := 0 - v := &M2{&i} // ERROR "&M2 literal does not escape" + v := &M2{&i} // ERROR "&M2{...} does not escape" var x M = v v1 := x.(*M2) _ = v1 } { i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&M2 literal escapes to heap" + v := &M2{&i} // ERROR "&M2{...} escapes to heap" // BAD: v does not escape to heap here var x M = v v1 := x.(*M2) @@ -173,7 +173,7 @@ func efaceEscape2() { } { i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&M2 literal does not escape" + v := &M2{&i} // ERROR "&M2{...} does not escape" // BAD: v does not escape to heap here var x M = v v1 := x.(*M2) @@ -181,7 +181,7 @@ func efaceEscape2() { } { i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&M2 literal does not escape" + v := &M2{&i} // ERROR "&M2{...} does not escape" // BAD: v does not escape to heap here var x M = v v1, ok := x.(*M2) @@ -190,20 +190,20 @@ func efaceEscape2() { } { i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&M2 literal escapes to heap" + v := &M2{&i} // ERROR "&M2{...} escapes to heap" // BAD: v does not escape to heap here var x M = v x.M() } { i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&M2 literal escapes to heap" + v := &M2{&i} // ERROR "&M2{...} escapes to heap" var x M = v mescapes(x) } { i := 0 - v := &M2{&i} // ERROR "&M2 literal does not escape" + v := &M2{&i} // ERROR "&M2{...} does not escape" var x M = v mdoesnotescape(x) } @@ -219,8 +219,8 @@ type T2 struct { func dotTypeEscape() *T2 { // #11931 var x interface{} - x = &T1{p: new(int)} // ERROR "new\(int\) escapes to heap" "&T1 literal does not escape" - return &T2{ // ERROR "&T2 literal escapes to heap" + x = &T1{p: new(int)} // ERROR "new\(int\) escapes to heap" "&T1{...} does not escape" + return &T2{ // ERROR "&T2{...} escapes to heap" T1: *(x.(*T1)), } } @@ -244,7 +244,7 @@ func dotTypeEscape2() { // #13805, #15796 var x interface{} = i // ERROR "i does not escape" var y interface{} = j // ERROR "j does not escape" - sink = x.(int) // ERROR "x.\(int\) escapes to heap" + sink = x.(int) // ERROR "x.\(int\) escapes to heap" sink, *(&ok) = y.(int) } { diff --git a/test/escape_indir.go b/test/escape_indir.go index 19889f259f..12005e35f9 100644 --- a/test/escape_indir.go +++ b/test/escape_indir.go @@ -23,7 +23,7 @@ type ConstPtr2 struct { func constptr0() { i := 0 // ERROR "moved to heap: i" - x := &ConstPtr{} // ERROR "&ConstPtr literal does not escape" + x := &ConstPtr{} // ERROR "&ConstPtr{} does not escape" // BAD: i should not escape here x.p = &i _ = x @@ -31,55 +31,55 @@ func constptr0() { func constptr01() *ConstPtr { i := 0 // ERROR "moved to heap: i" - x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap" + x := &ConstPtr{} // ERROR "&ConstPtr{} escapes to heap" x.p = &i return x } func constptr02() ConstPtr { i := 0 // ERROR "moved to heap: i" - x := &ConstPtr{} // ERROR "&ConstPtr literal does not escape" + x := &ConstPtr{} // ERROR "&ConstPtr{} does not escape" x.p = &i return *x } func constptr03() **ConstPtr { i := 0 // ERROR "moved to heap: i" - x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap" "moved to heap: x" + x := &ConstPtr{} // ERROR "&ConstPtr{} escapes to heap" "moved to heap: x" x.p = &i return &x } func constptr1() { i := 0 // ERROR "moved to heap: i" - x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap" + x := &ConstPtr{} // ERROR "&ConstPtr{} escapes to heap" x.p = &i sink = x } func constptr2() { i := 0 // ERROR "moved to heap: i" - x := &ConstPtr{} // ERROR "&ConstPtr literal does not escape" + x := &ConstPtr{} // ERROR "&ConstPtr{} does not escape" x.p = &i - sink = *x // ERROR "\*x escapes to heap" + sink = *x // ERROR "\*x escapes to heap" } func constptr4() *ConstPtr { p := new(ConstPtr) // ERROR "new\(ConstPtr\) escapes to heap" - *p = *&ConstPtr{} // ERROR "&ConstPtr literal does not escape" + *p = *&ConstPtr{} // ERROR "&ConstPtr{} does not escape" return p } func constptr5() *ConstPtr { p := new(ConstPtr) // ERROR "new\(ConstPtr\) escapes to heap" - p1 := &ConstPtr{} // ERROR "&ConstPtr literal does not escape" + p1 := &ConstPtr{} // ERROR "&ConstPtr{} does not escape" *p = *p1 return p } // BAD: p should not escape here func constptr6(p *ConstPtr) { // ERROR "leaking param content: p" - p1 := &ConstPtr{} // ERROR "&ConstPtr literal does not escape" + p1 := &ConstPtr{} // ERROR "&ConstPtr{} does not escape" *p1 = *p _ = p1 } @@ -102,17 +102,17 @@ func constptr8() *ConstPtr { func constptr9() ConstPtr { p := new(ConstPtr) // ERROR "new\(ConstPtr\) does not escape" var p1 ConstPtr2 - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" p1.p = &i p.c = p1 return *p } func constptr10() ConstPtr { - x := &ConstPtr{} // ERROR "moved to heap: x" "&ConstPtr literal escapes to heap" + x := &ConstPtr{} // ERROR "moved to heap: x" "&ConstPtr{} escapes to heap" i := 0 // ERROR "moved to heap: i" var p *ConstPtr - p = &ConstPtr{p: &i, x: &x} // ERROR "&ConstPtr literal does not escape" + p = &ConstPtr{p: &i, x: &x} // ERROR "&ConstPtr{...} does not escape" var pp **ConstPtr pp = &p return **pp @@ -121,7 +121,7 @@ func constptr10() ConstPtr { func constptr11() *ConstPtr { i := 0 // ERROR "moved to heap: i" p := new(ConstPtr) // ERROR "new\(ConstPtr\) escapes to heap" - p1 := &ConstPtr{} // ERROR "&ConstPtr literal does not escape" + p1 := &ConstPtr{} // ERROR "&ConstPtr{} does not escape" p1.p = &i *p = *p1 return p @@ -134,7 +134,7 @@ func foo(p **int) { // ERROR "p does not escape" } func foo1(p *int) { // ERROR "p does not escape" - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" y := &p *y = &i } @@ -148,13 +148,13 @@ func foo2() { var z Z z.f = &x p := z.f - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" *p = &i } var global *byte func f() { - var x byte // ERROR "moved to heap: x" + var x byte // ERROR "moved to heap: x" global = &*&x } diff --git a/test/escape_map.go b/test/escape_map.go index 0e9896a9fc..23abaa1e0c 100644 --- a/test/escape_map.go +++ b/test/escape_map.go @@ -15,7 +15,7 @@ func map0() { // BAD: i should not escape i := 0 // ERROR "moved to heap: i" // BAD: j should not escape - j := 0 // ERROR "moved to heap: j" + j := 0 // ERROR "moved to heap: j" m[&i] = &j _ = m } @@ -23,8 +23,8 @@ func map0() { func map1() *int { m := make(map[*int]*int) // ERROR "make\(map\[\*int\]\*int\) does not escape" // BAD: i should not escape - i := 0 // ERROR "moved to heap: i" - j := 0 // ERROR "moved to heap: j" + i := 0 // ERROR "moved to heap: i" + j := 0 // ERROR "moved to heap: j" m[&i] = &j return m[&i] } @@ -41,7 +41,7 @@ func map3() []*int { m := make(map[*int]*int) // ERROR "make\(map\[\*int\]\*int\) does not escape" i := 0 // ERROR "moved to heap: i" // BAD: j should not escape - j := 0 // ERROR "moved to heap: j" + j := 0 // ERROR "moved to heap: j" m[&i] = &j var r []*int for k := range m { @@ -53,8 +53,8 @@ func map3() []*int { func map4() []*int { m := make(map[*int]*int) // ERROR "make\(map\[\*int\]\*int\) does not escape" // BAD: i should not escape - i := 0 // ERROR "moved to heap: i" - j := 0 // ERROR "moved to heap: j" + i := 0 // ERROR "moved to heap: i" + j := 0 // ERROR "moved to heap: j" m[&i] = &j var r []*int for k, v := range m { @@ -68,8 +68,8 @@ func map4() []*int { } func map5(m map[*int]*int) { // ERROR "m does not escape" - i := 0 // ERROR "moved to heap: i" - j := 0 // ERROR "moved to heap: j" + i := 0 // ERROR "moved to heap: i" + j := 0 // ERROR "moved to heap: j" m[&i] = &j } @@ -77,8 +77,8 @@ func map6(m map[*int]*int) { // ERROR "m does not escape" if m != nil { m = make(map[*int]*int) // ERROR "make\(map\[\*int\]\*int\) does not escape" } - i := 0 // ERROR "moved to heap: i" - j := 0 // ERROR "moved to heap: j" + i := 0 // ERROR "moved to heap: i" + j := 0 // ERROR "moved to heap: j" m[&i] = &j } @@ -87,14 +87,14 @@ func map7() { i := 0 // ERROR "moved to heap: i" // BAD: j should not escape j := 0 // ERROR "moved to heap: j" - m := map[*int]*int{&i: &j} // ERROR "literal does not escape" + m := map[*int]*int{&i: &j} // ERROR "map\[\*int\]\*int{...} does not escape" _ = m } func map8() { i := 0 // ERROR "moved to heap: i" j := 0 // ERROR "moved to heap: j" - m := map[*int]*int{&i: &j} // ERROR "literal escapes to heap" + m := map[*int]*int{&i: &j} // ERROR "map\[\*int\]\*int{...} escapes to heap" sink = m } @@ -102,6 +102,6 @@ func map9() *int { // BAD: i should not escape i := 0 // ERROR "moved to heap: i" j := 0 // ERROR "moved to heap: j" - m := map[*int]*int{&i: &j} // ERROR "literal does not escape" + m := map[*int]*int{&i: &j} // ERROR "map\[\*int\]\*int{...} does not escape" return m[nil] } diff --git a/test/escape_param.go b/test/escape_param.go index d8fafc53f8..993e914e1d 100644 --- a/test/escape_param.go +++ b/test/escape_param.go @@ -26,7 +26,7 @@ func caller0a() { } func caller0b() { - i := 0 // ERROR "moved to heap: i$" + i := 0 // ERROR "moved to heap: i$" sink = param0(&i) } @@ -150,11 +150,11 @@ func caller3a() { } func caller3b() { - i := 0 // ERROR "moved to heap: i$" - j := 0 // ERROR "moved to heap: j$" + i := 0 // ERROR "moved to heap: i$" + j := 0 // ERROR "moved to heap: j$" p := Pair{&i, &j} param3(&p) - sink = p // ERROR "p escapes to heap$" + sink = p // ERROR "p escapes to heap$" } // in -> rcvr @@ -173,7 +173,7 @@ func caller4b() { i := 0 // ERROR "moved to heap: i$" p := Pair{} p.param4(&i) - sink = p // ERROR "p escapes to heap$" + sink = p // ERROR "p escapes to heap$" } // in -> heap @@ -182,7 +182,7 @@ func param5(i *int) { // ERROR "leaking param: i$" } func caller5() { - i := 0 // ERROR "moved to heap: i$" + i := 0 // ERROR "moved to heap: i$" param5(&i) } @@ -192,8 +192,8 @@ func param6(i ***int) { // ERROR "leaking param content: i$" } func caller6a() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p$" + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" p2 := &p param6(&p2) } @@ -204,7 +204,7 @@ func param7(i ***int) { // ERROR "leaking param content: i$" } func caller7() { - i := 0 // ERROR "moved to heap: i$" + i := 0 // ERROR "moved to heap: i$" p := &i p2 := &p param7(&p2) @@ -234,8 +234,8 @@ func caller9a() { } func caller9b() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p$" + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" p2 := &p sink = param9(&p2) } @@ -253,7 +253,7 @@ func caller10a() { } func caller10b() { - i := 0 // ERROR "moved to heap: i$" + i := 0 // ERROR "moved to heap: i$" p := &i p2 := &p sink = param10(&p2) @@ -265,26 +265,26 @@ func param11(i **int) ***int { // ERROR "moved to heap: i$" } func caller11a() { - i := 0 // ERROR "moved to heap: i" - p := &i // ERROR "moved to heap: p" + i := 0 // ERROR "moved to heap: i" + p := &i // ERROR "moved to heap: p" _ = param11(&p) } func caller11b() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p$" + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p$" sink = param11(&p) } func caller11c() { // GOOD - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p" + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p" sink = *param11(&p) } func caller11d() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p" + i := 0 // ERROR "moved to heap: i$" + p := &i // ERROR "moved to heap: p" p2 := &p sink = param11(p2) } @@ -309,7 +309,7 @@ func caller12a() { func caller12b() { i := 0 // ERROR "moved to heap: i$" p := &i // ERROR "moved to heap: p$" - r := &Indir{} // ERROR "&Indir literal does not escape$" + r := &Indir{} // ERROR "&Indir{} does not escape$" r.param12(&p) _ = r } @@ -359,7 +359,7 @@ func caller13b() { func caller13c() { i := 0 // ERROR "moved to heap: i$" var p *int - v := &Val{&p} // ERROR "&Val literal does not escape$" + v := &Val{&p} // ERROR "&Val{...} does not escape$" v.param13(&i) _ = v } @@ -374,8 +374,8 @@ func caller13d() { } func caller13e() { - i := 0 // ERROR "moved to heap: i$" - var p *int // ERROR "moved to heap: p$" + i := 0 // ERROR "moved to heap: i$" + var p *int // ERROR "moved to heap: p$" v := Val{&p} v.param13(&i) sink = v @@ -384,7 +384,7 @@ func caller13e() { func caller13f() { i := 0 // ERROR "moved to heap: i$" var p *int // ERROR "moved to heap: p$" - v := &Val{&p} // ERROR "&Val literal escapes to heap$" + v := &Val{&p} // ERROR "&Val{...} escapes to heap$" v.param13(&i) sink = v } @@ -400,9 +400,9 @@ func caller13g() { func caller13h() { i := 0 // ERROR "moved to heap: i$" var p *int - v := &Val{&p} // ERROR "&Val literal does not escape$" + v := &Val{&p} // ERROR "&Val{...} does not escape$" v.param13(&i) - sink = **v.p // ERROR "\* \(\*v\.p\) escapes to heap" + sink = **v.p // ERROR "\* \(\*v\.p\) escapes to heap" } type Node struct { @@ -412,15 +412,15 @@ type Node struct { var Sink *Node func f(x *Node) { // ERROR "leaking param content: x" - Sink = &Node{x.p} // ERROR "&Node literal escapes to heap" + Sink = &Node{x.p} // ERROR "&Node{...} escapes to heap" } func g(x *Node) *Node { // ERROR "leaking param content: x" - return &Node{x.p} // ERROR "&Node literal escapes to heap" + return &Node{x.p} // ERROR "&Node{...} escapes to heap" } func h(x *Node) { // ERROR "leaking param: x" - y := &Node{x} // ERROR "&Node literal does not escape" + y := &Node{x} // ERROR "&Node{...} does not escape" Sink = g(y) f(y) } diff --git a/test/escape_slice.go b/test/escape_slice.go index d2cdaa6a01..6ce852e9c5 100644 --- a/test/escape_slice.go +++ b/test/escape_slice.go @@ -77,19 +77,19 @@ func slice7() *int { func slice8() { i := 0 - s := []*int{&i} // ERROR "literal does not escape" + s := []*int{&i} // ERROR "\[\]\*int{...} does not escape" _ = s } func slice9() *int { i := 0 // ERROR "moved to heap: i" - s := []*int{&i} // ERROR "literal does not escape" + s := []*int{&i} // ERROR "\[\]\*int{...} does not escape" return s[0] } func slice10() []*int { i := 0 // ERROR "moved to heap: i" - s := []*int{&i} // ERROR "literal escapes to heap" + s := []*int{&i} // ERROR "\[\]\*int{...} escapes to heap" return s } @@ -103,7 +103,7 @@ func slice11() { func envForDir(dir string) []string { // ERROR "dir does not escape" env := os.Environ() - return mergeEnvLists([]string{"PWD=" + dir}, env) // ERROR ".PWD=. \+ dir escapes to heap" "\[\]string literal does not escape" + return mergeEnvLists([]string{"PWD=" + dir}, env) // ERROR ".PWD=. \+ dir escapes to heap" "\[\]string{...} does not escape" } func mergeEnvLists(in, out []string) []string { // ERROR "leaking param content: in" "leaking param content: out" "leaking param: out to result ~r2 level=0" @@ -160,14 +160,14 @@ var resolveIPAddrTests = []resolveIPAddrTest{ func setupTestData() { resolveIPAddrTests = append(resolveIPAddrTests, - []resolveIPAddrTest{ // ERROR "\[\]resolveIPAddrTest literal does not escape" + []resolveIPAddrTest{ // ERROR "\[\]resolveIPAddrTest{...} does not escape" {"ip", "localhost", - &IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr literal escapes to heap" + &IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr{...} escapes to heap" nil}, {"ip4", "localhost", - &IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr literal escapes to heap" + &IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr{...} escapes to heap" nil}, }...) } diff --git a/test/escape_struct_param1.go b/test/escape_struct_param1.go index 70b36191ab..496172c166 100644 --- a/test/escape_struct_param1.go +++ b/test/escape_struct_param1.go @@ -35,27 +35,27 @@ func (u *U) SPPi() *string { // ERROR "leaking param: u to result ~r0 level=2$" } func tSPPi() { - s := "cat" // ERROR "moved to heap: s$" + s := "cat" // ERROR "moved to heap: s$" ps := &s pps := &ps - pu := &U{ps, pps} // ERROR "&U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U{...} does not escape$" Ssink = pu.SPPi() } func tiSPP() { - s := "cat" // ERROR "moved to heap: s$" + s := "cat" // ERROR "moved to heap: s$" ps := &s pps := &ps - pu := &U{ps, pps} // ERROR "&U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U{...} does not escape$" Ssink = *pu.SPP() } // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of ps func tSP() { - s := "cat" // ERROR "moved to heap: s$" - ps := &s // ERROR "moved to heap: ps$" + s := "cat" // ERROR "moved to heap: s$" + ps := &s // ERROR "moved to heap: ps$" pps := &ps - pu := &U{ps, pps} // ERROR "&U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U{...} does not escape$" Ssink = pu.SP() } @@ -114,72 +114,72 @@ func (v *V) UPiSPd() *string { // ERROR "leaking param: v to result ~r0 level=2$ // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3 func tUPiSPa() { s1 := "ant" - s2 := "bat" // ERROR "moved to heap: s2$" - s3 := "cat" // ERROR "moved to heap: s3$" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s2 := "bat" // ERROR "moved to heap: s2$" + s3 := "cat" // ERROR "moved to heap: s3$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 - ps4 := &s4 // ERROR "moved to heap: ps4$" - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPa() // Ssink = &s3 (only &s3 really escapes) } // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3 func tUPiSPb() { s1 := "ant" - s2 := "bat" // ERROR "moved to heap: s2$" - s3 := "cat" // ERROR "moved to heap: s3$" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s2 := "bat" // ERROR "moved to heap: s2$" + s3 := "cat" // ERROR "moved to heap: s3$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 - ps4 := &s4 // ERROR "moved to heap: ps4$" - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPb() // Ssink = &s3 (only &s3 really escapes) } // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3 func tUPiSPc() { s1 := "ant" - s2 := "bat" // ERROR "moved to heap: s2$" - s3 := "cat" // ERROR "moved to heap: s3$" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s2 := "bat" // ERROR "moved to heap: s2$" + s3 := "cat" // ERROR "moved to heap: s3$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 - ps4 := &s4 // ERROR "moved to heap: ps4$" - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPc() // Ssink = &s3 (only &s3 really escapes) } // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3 func tUPiSPd() { s1 := "ant" - s2 := "bat" // ERROR "moved to heap: s2$" - s3 := "cat" // ERROR "moved to heap: s3$" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s2 := "bat" // ERROR "moved to heap: s2$" + s3 := "cat" // ERROR "moved to heap: s3$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 - ps4 := &s4 // ERROR "moved to heap: ps4$" - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPd() // Ssink = &s3 (only &s3 really escapes) } @@ -204,16 +204,16 @@ func tUPiSPPia() { s1 := "ant" s2 := "bat" s3 := "cat" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 ps4 := &s4 - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPPia() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -222,16 +222,16 @@ func tUPiSPPib() { s1 := "ant" s2 := "bat" s3 := "cat" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 ps4 := &s4 - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPPib() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -240,16 +240,16 @@ func tUPiSPPic() { s1 := "ant" s2 := "bat" s3 := "cat" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 ps4 := &s4 - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPPic() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -258,16 +258,16 @@ func tUPiSPPid() { s1 := "ant" s2 := "bat" s3 := "cat" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 ps4 := &s4 - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -286,13 +286,13 @@ func tUPPiSPPia() { s3 := "cat" s4 := "dog" s5 := "emu" - s6 := "fox" // ERROR "moved to heap: s6$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 ps4 := &s4 ps6 := &s6 u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPPiSPPia() // Ssink = *&ps6 = &s6 (only &s6 really escapes) } diff --git a/test/escape_struct_param2.go b/test/escape_struct_param2.go index e42be79793..946397ea9f 100644 --- a/test/escape_struct_param2.go +++ b/test/escape_struct_param2.go @@ -35,27 +35,27 @@ func (u U) SPPi() *string { // ERROR "leaking param: u to result ~r0 level=1$" } func tSPPi() { - s := "cat" // ERROR "moved to heap: s$" + s := "cat" // ERROR "moved to heap: s$" ps := &s pps := &ps - pu := &U{ps, pps} // ERROR "&U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U{...} does not escape$" Ssink = pu.SPPi() } func tiSPP() { - s := "cat" // ERROR "moved to heap: s$" + s := "cat" // ERROR "moved to heap: s$" ps := &s pps := &ps - pu := &U{ps, pps} // ERROR "&U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U{...} does not escape$" Ssink = *pu.SPP() } // BAD: need fine-grained analysis to avoid spurious escape of ps func tSP() { - s := "cat" // ERROR "moved to heap: s$" - ps := &s // ERROR "moved to heap: ps$" + s := "cat" // ERROR "moved to heap: s$" + ps := &s // ERROR "moved to heap: ps$" pps := &ps - pu := &U{ps, pps} // ERROR "&U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U{...} does not escape$" Ssink = pu.SP() } @@ -114,72 +114,72 @@ func (v V) UPiSPd() *string { // ERROR "leaking param: v to result ~r0 level=1$" // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3 func tUPiSPa() { s1 := "ant" - s2 := "bat" // ERROR "moved to heap: s2$" - s3 := "cat" // ERROR "moved to heap: s3$" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s2 := "bat" // ERROR "moved to heap: s2$" + s3 := "cat" // ERROR "moved to heap: s3$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 - ps4 := &s4 // ERROR "moved to heap: ps4$" - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPa() // Ssink = &s3 (only &s3 really escapes) } // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3 func tUPiSPb() { s1 := "ant" - s2 := "bat" // ERROR "moved to heap: s2$" - s3 := "cat" // ERROR "moved to heap: s3$" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s2 := "bat" // ERROR "moved to heap: s2$" + s3 := "cat" // ERROR "moved to heap: s3$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 - ps4 := &s4 // ERROR "moved to heap: ps4$" - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPb() // Ssink = &s3 (only &s3 really escapes) } // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3 func tUPiSPc() { s1 := "ant" - s2 := "bat" // ERROR "moved to heap: s2$" - s3 := "cat" // ERROR "moved to heap: s3$" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s2 := "bat" // ERROR "moved to heap: s2$" + s3 := "cat" // ERROR "moved to heap: s3$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 - ps4 := &s4 // ERROR "moved to heap: ps4$" - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPc() // Ssink = &s3 (only &s3 really escapes) } // BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3 func tUPiSPd() { s1 := "ant" - s2 := "bat" // ERROR "moved to heap: s2$" - s3 := "cat" // ERROR "moved to heap: s3$" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s2 := "bat" // ERROR "moved to heap: s2$" + s3 := "cat" // ERROR "moved to heap: s3$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 - ps4 := &s4 // ERROR "moved to heap: ps4$" - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps4 := &s4 // ERROR "moved to heap: ps4$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal escapes to heap$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} escapes to heap$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPd() // Ssink = &s3 (only &s3 really escapes) } @@ -204,16 +204,16 @@ func tUPiSPPia() { s1 := "ant" s2 := "bat" s3 := "cat" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 ps4 := &s4 - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPPia() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -222,16 +222,16 @@ func tUPiSPPib() { s1 := "ant" s2 := "bat" s3 := "cat" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 ps4 := &s4 - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPPib() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -240,16 +240,16 @@ func tUPiSPPic() { s1 := "ant" s2 := "bat" s3 := "cat" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 ps4 := &s4 - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPPic() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -258,16 +258,16 @@ func tUPiSPPid() { s1 := "ant" s2 := "bat" s3 := "cat" - s4 := "dog" // ERROR "moved to heap: s4$" - s5 := "emu" // ERROR "moved to heap: s5$" - s6 := "fox" // ERROR "moved to heap: s6$" + s4 := "dog" // ERROR "moved to heap: s4$" + s5 := "emu" // ERROR "moved to heap: s5$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 ps4 := &s4 - ps6 := &s6 // ERROR "moved to heap: ps6$" + ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -286,13 +286,13 @@ func tUPPiSPPia() { // This test is sensitive to the level cap in function summa s3 := "cat" s4 := "dog" s5 := "emu" - s6 := "fox" // ERROR "moved to heap: s6$" + s6 := "fox" // ERROR "moved to heap: s6$" ps2 := &s2 ps4 := &s4 ps6 := &s6 u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "&U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "&U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" + u2 := &U{&s3, &ps4} // ERROR "&U{...} does not escape$" + u3 := &U{&s5, &ps6} // ERROR "&U{...} does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V{...} does not escape$" Ssink = v.UPPiSPPia() // Ssink = *&ps6 = &s6 (only &s6 really escapes) } diff --git a/test/fixedbugs/issue12006.go b/test/fixedbugs/issue12006.go index c44f2e5547..0a2ef8dad0 100644 --- a/test/fixedbugs/issue12006.go +++ b/test/fixedbugs/issue12006.go @@ -144,7 +144,7 @@ func TFooK2() { a := int32(1) // ERROR "moved to heap: a" b := "cat" c := &a - fs := fakeSlice{3, &[4]interface{}{a, b, c, nil}} // ERROR "a escapes to heap" "b escapes to heap" "&\[4\]interface {} literal does not escape" + fs := fakeSlice{3, &[4]interface{}{a, b, c, nil}} // ERROR "a escapes to heap" "b escapes to heap" "&\[4\]interface {}{...} does not escape" isink = FooK(fs) } @@ -169,6 +169,6 @@ func TFooL2() { a := int32(1) // ERROR "moved to heap: a" b := "cat" c := &a - s := []interface{}{a, b, c} // ERROR "a escapes to heap" "b escapes to heap" "\[\]interface {} literal does not escape" + s := []interface{}{a, b, c} // ERROR "a escapes to heap" "b escapes to heap" "\[\]interface {}{...} does not escape" isink = FooL(s) } diff --git a/test/fixedbugs/issue13799.go b/test/fixedbugs/issue13799.go index 5c57494777..fbdd4c32bc 100644 --- a/test/fixedbugs/issue13799.go +++ b/test/fixedbugs/issue13799.go @@ -162,7 +162,7 @@ func test5(iter int) { var fn *str for i := 0; i < maxI; i++ { // var fn *str // this makes it work, because fn stays off heap - fn = &str{m} // ERROR "&str literal escapes to heap" + fn = &str{m} // ERROR "&str{...} escapes to heap" recur1(0, fn) } @@ -180,7 +180,7 @@ func test6(iter int) { // var fn *str for i := 0; i < maxI; i++ { var fn *str // this makes it work, because fn stays off heap - fn = &str{m} // ERROR "&str literal does not escape" + fn = &str{m} // ERROR "&str{...} does not escape" recur1(0, fn) } diff --git a/test/fixedbugs/issue17645.go b/test/fixedbugs/issue17645.go index af785eae2a..95fcecd1e0 100644 --- a/test/fixedbugs/issue17645.go +++ b/test/fixedbugs/issue17645.go @@ -12,5 +12,5 @@ type Foo struct { func main() { var s []int - var _ string = append(s, Foo{""}) // ERROR "cannot use .. \(type untyped string\) as type int in field value" "cannot use Foo literal \(type Foo\) as type int in append" "cannot use append\(s\, Foo literal\) \(type \[\]int\) as type string in assignment" + var _ string = append(s, Foo{""}) // ERROR "cannot use .. \(type untyped string\) as type int in field value" "cannot use Foo{...} \(type Foo\) as type int in append" "cannot use append\(s\, Foo{...}\) \(type \[\]int\) as type string in assignment" } diff --git a/test/fixedbugs/issue21709.go b/test/fixedbugs/issue21709.go index cc5896ab53..20be10e792 100644 --- a/test/fixedbugs/issue21709.go +++ b/test/fixedbugs/issue21709.go @@ -16,7 +16,7 @@ var N int func F1() { var s S for i := 0; i < N; i++ { - fs := []func(){ // ERROR "\[\]func\(\) literal does not escape" + fs := []func(){ // ERROR "\[\]func\(\){...} does not escape" s.Inc, // ERROR "s.Inc does not escape" } for _, f := range fs { @@ -28,7 +28,7 @@ func F1() { func F2() { var s S for i := 0; i < N; i++ { - for _, f := range []func(){ // ERROR "\[\]func\(\) literal does not escape" + for _, f := range []func(){ // ERROR "\[\]func\(\){...} does not escape" s.Inc, // ERROR "s.Inc does not escape" } { f() diff --git a/test/fixedbugs/issue23732.go b/test/fixedbugs/issue23732.go index be17bf4f61..5e63eb2074 100644 --- a/test/fixedbugs/issue23732.go +++ b/test/fixedbugs/issue23732.go @@ -24,19 +24,19 @@ func main() { _ = Foo{ 1, 2, - 3, // ERROR "too few values in Foo literal" + 3, // ERROR "too few values in Foo{...}" } _ = Foo{ 1, 2, 3, - Bar{"A", "B"}, // ERROR "too many values in Bar literal" + Bar{"A", "B"}, // ERROR "too many values in Bar{...}" } _ = Foo{ 1, 2, - Bar{"A", "B"}, // ERROR "too many values in Bar literal" "too few values in Foo literal" + Bar{"A", "B"}, // ERROR "too many values in Bar{...}" "too few values in Foo{...}" } } diff --git a/test/fixedbugs/issue26855.go b/test/fixedbugs/issue26855.go index d5b95ddbf1..144e4415f7 100644 --- a/test/fixedbugs/issue26855.go +++ b/test/fixedbugs/issue26855.go @@ -20,9 +20,9 @@ type P struct { type T struct{} var _ = S{ - f: &T{}, // ERROR "cannot use &T literal" + f: &T{}, // ERROR "cannot use &T{}" } var _ = P{ - f: T{}, // ERROR "cannot use T literal" + f: T{}, // ERROR "cannot use T{}" } diff --git a/test/fixedbugs/issue30898.go b/test/fixedbugs/issue30898.go index 012d5a2634..b6376d3f9e 100644 --- a/test/fixedbugs/issue30898.go +++ b/test/fixedbugs/issue30898.go @@ -15,5 +15,5 @@ func debugf(format string, args ...interface{}) { // ERROR "can inline debugf" " func bar() { // ERROR "can inline bar" value := 10 - debugf("value is %d", value) // ERROR "inlining call to debugf" "value does not escape" "\[\]interface {} literal does not escape" + debugf("value is %d", value) // ERROR "inlining call to debugf" "value does not escape" "\[\]interface {}{...} does not escape" } diff --git a/test/fixedbugs/issue31573.go b/test/fixedbugs/issue31573.go index c9ea84bbae..005910e00d 100644 --- a/test/fixedbugs/issue31573.go +++ b/test/fixedbugs/issue31573.go @@ -14,18 +14,18 @@ func g() { defer f(new(int), new(int)) // ERROR "... argument does not escape$" "new\(int\) does not escape$" defer f(nil...) - defer f([]*int{}...) // ERROR "\[\]\*int literal does not escape$" - defer f([]*int{new(int)}...) // ERROR "\[\]\*int literal does not escape$" "new\(int\) does not escape$" - defer f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int literal does not escape$" "new\(int\) does not escape$" + defer f([]*int{}...) // ERROR "\[\]\*int{} does not escape$" + defer f([]*int{new(int)}...) // ERROR "\[\]\*int{...} does not escape$" "new\(int\) does not escape$" + defer f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int{...} does not escape$" "new\(int\) does not escape$" go f() go f(new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" go f(new(int), new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" go f(nil...) - go f([]*int{}...) // ERROR "\[\]\*int literal escapes to heap$" - go f([]*int{new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" - go f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" + go f([]*int{}...) // ERROR "\[\]\*int{} escapes to heap$" + go f([]*int{new(int)}...) // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$" + go f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$" for { defer f() @@ -33,17 +33,17 @@ func g() { defer f(new(int), new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" defer f(nil...) - defer f([]*int{}...) // ERROR "\[\]\*int literal escapes to heap$" - defer f([]*int{new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" - defer f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" + defer f([]*int{}...) // ERROR "\[\]\*int{} escapes to heap$" + defer f([]*int{new(int)}...) // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$" + defer f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$" go f() go f(new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" go f(new(int), new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" go f(nil...) - go f([]*int{}...) // ERROR "\[\]\*int literal escapes to heap$" - go f([]*int{new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" - go f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" + go f([]*int{}...) // ERROR "\[\]\*int{} escapes to heap$" + go f([]*int{new(int)}...) // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$" + go f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int{...} escapes to heap$" "new\(int\) escapes to heap$" } } diff --git a/test/fixedbugs/issue38745.go b/test/fixedbugs/issue38745.go new file mode 100644 index 0000000000..21bd1ff3a7 --- /dev/null +++ b/test/fixedbugs/issue38745.go @@ -0,0 +1,19 @@ +// errorcheck + +// Copyright 2020 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 p + +type t struct{ x int } + +func f1() { + t{}.M() // ERROR "t{}.M undefined \(type t has no field or method M\)" + t{x: 1}.M() // ERROR "t{...}.M undefined \(type t has no field or method M\)" +} + +func f2() (*t, error) { + // BAD: should report undefined error only. + return t{}.M() // ERROR "t{}.M undefined \(type t has no field or method M\)" "not enough arguments to return" +} diff --git a/test/fixedbugs/issue39292.go b/test/fixedbugs/issue39292.go index 1be88653e9..7dac2e5fc6 100644 --- a/test/fixedbugs/issue39292.go +++ b/test/fixedbugs/issue39292.go @@ -12,18 +12,18 @@ func (t) f() { } func x() { - x := t{}.f // ERROR "t literal.f escapes to heap" + x := t{}.f // ERROR "t{}.f escapes to heap" x() } func y() { var i int // ERROR "moved to heap: i" - y := (&t{&i}).f // ERROR "\(&t literal\).f escapes to heap" "&t literal escapes to heap" + y := (&t{&i}).f // ERROR "\(&t{...}\).f escapes to heap" "&t{...} escapes to heap" y() } func z() { var i int // ERROR "moved to heap: i" - z := t{&i}.f // ERROR "t literal.f escapes to heap" + z := t{&i}.f // ERROR "t{...}.f escapes to heap" z() } diff --git a/test/fixedbugs/issue41247.go b/test/fixedbugs/issue41247.go index 2df919c9e6..b8bd81274f 100644 --- a/test/fixedbugs/issue41247.go +++ b/test/fixedbugs/issue41247.go @@ -7,5 +7,5 @@ package p func f() [2]int { - return [...]int{2: 0} // ERROR "cannot use \[\.\.\.\]int literal \(type \[3\]int\)" + return [...]int{2: 0} // ERROR "cannot use \[\.\.\.\]int{...} \(type \[3\]int\)" } diff --git a/test/fixedbugs/issue7921.go b/test/fixedbugs/issue7921.go index a8efc8dd9e..5dce557ca3 100644 --- a/test/fixedbugs/issue7921.go +++ b/test/fixedbugs/issue7921.go @@ -18,12 +18,12 @@ func bufferNotEscape() string { // can be stack-allocated. var b bytes.Buffer b.WriteString("123") - b.Write([]byte{'4'}) // ERROR "\[\]byte literal does not escape$" + b.Write([]byte{'4'}) // ERROR "\[\]byte{...} does not escape$" return b.String() // ERROR "inlining call to bytes.\(\*Buffer\).String$" "string\(bytes.b.buf\[bytes.b.off:\]\) escapes to heap$" } func bufferNoEscape2(xs []string) int { // ERROR "xs does not escape$" - b := bytes.NewBuffer(make([]byte, 0, 64)) // ERROR "&bytes.Buffer literal does not escape$" "make\(\[\]byte, 0, 64\) does not escape$" "inlining call to bytes.NewBuffer$" + b := bytes.NewBuffer(make([]byte, 0, 64)) // ERROR "&bytes.Buffer{...} does not escape$" "make\(\[\]byte, 0, 64\) does not escape$" "inlining call to bytes.NewBuffer$" for _, x := range xs { b.WriteString(x) } @@ -31,7 +31,7 @@ func bufferNoEscape2(xs []string) int { // ERROR "xs does not escape$" } func bufferNoEscape3(xs []string) string { // ERROR "xs does not escape$" - b := bytes.NewBuffer(make([]byte, 0, 64)) // ERROR "&bytes.Buffer literal does not escape$" "make\(\[\]byte, 0, 64\) does not escape$" "inlining call to bytes.NewBuffer$" + b := bytes.NewBuffer(make([]byte, 0, 64)) // ERROR "&bytes.Buffer{...} does not escape$" "make\(\[\]byte, 0, 64\) does not escape$" "inlining call to bytes.NewBuffer$" for _, x := range xs { b.WriteString(x) b.WriteByte(',') @@ -41,13 +41,13 @@ func bufferNoEscape3(xs []string) string { // ERROR "xs does not escape$" func bufferNoEscape4() []byte { var b bytes.Buffer - b.Grow(64) // ERROR "bufferNoEscape4 ignoring self-assignment in bytes.b.buf = bytes.b.buf\[:bytes.m·3\]$" "inlining call to bytes.\(\*Buffer\).Grow$" + b.Grow(64) // ERROR "bufferNoEscape4 ignoring self-assignment in bytes.b.buf = bytes.b.buf\[:bytes.m·3\]$" "inlining call to bytes.\(\*Buffer\).Grow$" useBuffer(&b) return b.Bytes() // ERROR "inlining call to bytes.\(\*Buffer\).Bytes$" } func bufferNoEscape5() { // ERROR "can inline bufferNoEscape5$" - b := bytes.NewBuffer(make([]byte, 0, 128)) // ERROR "&bytes.Buffer literal does not escape$" "make\(\[\]byte, 0, 128\) does not escape$" "inlining call to bytes.NewBuffer$" + b := bytes.NewBuffer(make([]byte, 0, 128)) // ERROR "&bytes.Buffer{...} does not escape$" "make\(\[\]byte, 0, 128\) does not escape$" "inlining call to bytes.NewBuffer$" useBuffer(b) } diff --git a/test/inline_variadic.go b/test/inline_variadic.go index fcc1cff1e8..687048a192 100644 --- a/test/inline_variadic.go +++ b/test/inline_variadic.go @@ -14,6 +14,6 @@ func head(xs ...string) string { // ERROR "can inline head" "leaking param: xs t } func f() string { // ERROR "can inline f" - x := head("hello", "world") // ERROR "inlining call to head" "\[\]string literal does not escape" + x := head("hello", "world") // ERROR "inlining call to head" "\[\]string{...} does not escape" return x } -- cgit v1.3 From 806f478499b57c5167fb5301101961b7563903d2 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Wed, 9 Sep 2020 16:25:48 +0700 Subject: cmd/compile: don't report not enough args error if call is undefined Fixes #38745 Change-Id: I2fbd8b512a8cf911b81a087162c74416116efea5 Reviewed-on: https://go-review.googlesource.com/c/go/+/253678 Run-TryBot: Cuong Manh Le TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/typecheck.go | 2 +- test/ddd1.go | 2 +- test/fixedbugs/issue38745.go | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index dec4b96fc4..fb169cfec8 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -2667,7 +2667,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *types.Type, nl Nodes, return notenough: - if n == nil || !n.Diag() { + if n == nil || (!n.Diag() && n.Type != nil) { details := errorDetails(nl, tstruct, isddd) if call != nil { // call is the expression being called, not the overall call. diff --git a/test/ddd1.go b/test/ddd1.go index 2c7e83e374..9857814648 100644 --- a/test/ddd1.go +++ b/test/ddd1.go @@ -29,7 +29,7 @@ var ( _ = sum(tuple()) _ = sum(tuple()...) // ERROR "multiple-value" _ = sum3(tuple()) - _ = sum3(tuple()...) // ERROR "multiple-value" "not enough" + _ = sum3(tuple()...) // ERROR "multiple-value" ) type T []T diff --git a/test/fixedbugs/issue38745.go b/test/fixedbugs/issue38745.go index 21bd1ff3a7..83a3bc6fad 100644 --- a/test/fixedbugs/issue38745.go +++ b/test/fixedbugs/issue38745.go @@ -14,6 +14,5 @@ func f1() { } func f2() (*t, error) { - // BAD: should report undefined error only. - return t{}.M() // ERROR "t{}.M undefined \(type t has no field or method M\)" "not enough arguments to return" + return t{}.M() // ERROR "t{}.M undefined \(type t has no field or method M\)" } -- cgit v1.3 From 1f4521669416a2e14fb0b84481447f4a93f19878 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sat, 12 Sep 2020 01:57:27 +0700 Subject: cmd/compile: attach OVARLIVE nodes to OCALLxxx So we can insert theses OVARLIVE nodes right after OpStaticCall in SSA. This helps fixing issue that unsafe-uintptr arguments are not kept alive during return statement, or can be kept alive longer than expected. Fixes #24491 Change-Id: Ic04a5d1bbb5c90dcfae65bd95cdd1da393a66800 Reviewed-on: https://go-review.googlesource.com/c/go/+/254397 Run-TryBot: Cuong Manh Le TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/order.go | 14 +++------ src/cmd/compile/internal/gc/ssa.go | 2 ++ src/cmd/compile/internal/gc/syntax.go | 4 +-- test/fixedbugs/issue24491.go | 45 ----------------------------- test/fixedbugs/issue24491a.go | 54 +++++++++++++++++++++++++++++++++++ test/fixedbugs/issue24491b.go | 46 +++++++++++++++++++++++++++++ 6 files changed, 107 insertions(+), 58 deletions(-) delete mode 100644 test/fixedbugs/issue24491.go create mode 100644 test/fixedbugs/issue24491a.go create mode 100644 test/fixedbugs/issue24491b.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index 412f073a8d..341f4ee66f 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -288,20 +288,13 @@ func (o *Order) popTemp(mark ordermarker) { o.temp = o.temp[:mark] } -// cleanTempNoPop emits VARKILL and if needed VARLIVE instructions -// to *out for each temporary above the mark on the temporary stack. +// cleanTempNoPop emits VARKILL instructions to *out +// for each temporary above the mark on the temporary stack. // It does not pop the temporaries from the stack. func (o *Order) cleanTempNoPop(mark ordermarker) []*Node { var out []*Node for i := len(o.temp) - 1; i >= int(mark); i-- { n := o.temp[i] - if n.Name.Keepalive() { - n.Name.SetKeepalive(false) - n.Name.SetAddrtaken(true) // ensure SSA keeps the n variable - live := nod(OVARLIVE, n, nil) - live = typecheck(live, ctxStmt) - out = append(out, live) - } kill := nod(OVARKILL, n, nil) kill = typecheck(kill, ctxStmt) out = append(out, kill) @@ -500,8 +493,9 @@ func (o *Order) call(n *Node) { // still alive when we pop the temp stack. if arg.Op == OCONVNOP && arg.Left.Type.IsUnsafePtr() { x := o.copyExpr(arg.Left, arg.Left.Type, false) - x.Name.SetKeepalive(true) arg.Left = x + x.Name.SetAddrtaken(true) // ensure SSA keeps the x variable + n.Nbody.Append(typecheck(nod(OVARLIVE, x, nil), ctxStmt)) n.SetNeedsWrapper(true) } } diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 89644cd3f2..3bdb5b0b9f 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -4498,6 +4498,8 @@ func (s *state) call(n *Node, k callKind) *ssa.Value { call.AuxInt = stksize // Call operations carry the argsize of the callee along with them } s.vars[&memVar] = call + // Insert OVARLIVE nodes + s.stmtList(n.Nbody) // Finish block for defers if k == callDefer || k == callDeferStack { diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index 5580f789c5..9592b7484c 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -374,7 +374,6 @@ const ( nameReadonly nameByval // is the variable captured by value or by reference nameNeedzero // if it contains pointers, needs to be zeroed on function entry - nameKeepalive // mark value live across unknown assembly call nameAutoTemp // is the variable a temporary (implies no dwarf info. reset if escapes to heap) nameUsed // for variable declared and not used error nameIsClosureVar // PAUTOHEAP closure pseudo-variable; original at n.Name.Defn @@ -391,7 +390,6 @@ func (n *Name) Captured() bool { return n.flags&nameCaptured != 0 } func (n *Name) Readonly() bool { return n.flags&nameReadonly != 0 } func (n *Name) Byval() bool { return n.flags&nameByval != 0 } func (n *Name) Needzero() bool { return n.flags&nameNeedzero != 0 } -func (n *Name) Keepalive() bool { return n.flags&nameKeepalive != 0 } func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 } func (n *Name) Used() bool { return n.flags&nameUsed != 0 } func (n *Name) IsClosureVar() bool { return n.flags&nameIsClosureVar != 0 } @@ -407,7 +405,6 @@ func (n *Name) SetCaptured(b bool) { n.flags.set(nameCaptured, b) } func (n *Name) SetReadonly(b bool) { n.flags.set(nameReadonly, b) } func (n *Name) SetByval(b bool) { n.flags.set(nameByval, b) } func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) } -func (n *Name) SetKeepalive(b bool) { n.flags.set(nameKeepalive, b) } func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) } func (n *Name) SetUsed(b bool) { n.flags.set(nameUsed, b) } func (n *Name) SetIsClosureVar(b bool) { n.flags.set(nameIsClosureVar, b) } @@ -707,6 +704,7 @@ const ( // Prior to walk, they are: Left(List), where List is all regular arguments. // After walk, List is a series of assignments to temporaries, // and Rlist is an updated set of arguments. + // Nbody is all OVARLIVE nodes that are attached to OCALLxxx. // TODO(josharian/khr): Use Ninit instead of List for the assignments to temporaries. See CL 114797. OCALLFUNC // Left(List/Rlist) (function call f(args)) OCALLMETH // Left(List/Rlist) (direct method call x.Method(args)) diff --git a/test/fixedbugs/issue24491.go b/test/fixedbugs/issue24491.go deleted file mode 100644 index 4703368793..0000000000 --- a/test/fixedbugs/issue24491.go +++ /dev/null @@ -1,45 +0,0 @@ -// run - -// Copyright 2020 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 test makes sure unsafe-uintptr arguments are handled correctly. - -package main - -import ( - "runtime" - "unsafe" -) - -var done = make(chan bool, 1) - -func setup() unsafe.Pointer { - s := "ok" - runtime.SetFinalizer(&s, func(p *string) { *p = "FAIL" }) - return unsafe.Pointer(&s) -} - -//go:noinline -//go:uintptrescapes -func test(s string, p uintptr) { - runtime.GC() - if *(*string)(unsafe.Pointer(p)) != "ok" { - panic(s + " return unexpected result") - } - done <- true -} - -func main() { - test("normal", uintptr(setup())) - <-done - - go test("go", uintptr(setup())) - <-done - - func() { - defer test("defer", uintptr(setup())) - }() - <-done -} diff --git a/test/fixedbugs/issue24491a.go b/test/fixedbugs/issue24491a.go new file mode 100644 index 0000000000..148134d187 --- /dev/null +++ b/test/fixedbugs/issue24491a.go @@ -0,0 +1,54 @@ +// run + +// Copyright 2020 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 test makes sure unsafe-uintptr arguments are handled correctly. + +package main + +import ( + "runtime" + "unsafe" +) + +var done = make(chan bool, 1) + +func setup() unsafe.Pointer { + s := "ok" + runtime.SetFinalizer(&s, func(p *string) { *p = "FAIL" }) + return unsafe.Pointer(&s) +} + +//go:noinline +//go:uintptrescapes +func test(s string, p uintptr) int { + runtime.GC() + if *(*string)(unsafe.Pointer(p)) != "ok" { + panic(s + " return unexpected result") + } + done <- true + return 0 +} + +//go:noinline +func f() int { + return test("return", uintptr(setup())) +} + +func main() { + test("normal", uintptr(setup())) + <-done + + go test("go", uintptr(setup())) + <-done + + func() { + defer test("defer", uintptr(setup())) + }() + <-done + + f() + <-done +} diff --git a/test/fixedbugs/issue24491b.go b/test/fixedbugs/issue24491b.go new file mode 100644 index 0000000000..5f4a2f233e --- /dev/null +++ b/test/fixedbugs/issue24491b.go @@ -0,0 +1,46 @@ +// run + +// Copyright 2020 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 test makes sure unsafe-uintptr arguments are not +// kept alive longer than expected. + +package main + +import ( + "runtime" + "sync/atomic" + "unsafe" +) + +var done uint32 + +func setup() unsafe.Pointer { + s := "ok" + runtime.SetFinalizer(&s, func(p *string) { atomic.StoreUint32(&done, 1) }) + return unsafe.Pointer(&s) +} + +//go:noinline +//go:uintptrescapes +func before(p uintptr) int { + runtime.GC() + if atomic.LoadUint32(&done) != 0 { + panic("GC early") + } + return 0 +} + +func after() int { + runtime.GC() + if atomic.LoadUint32(&done) == 0 { + panic("GC late") + } + return 0 +} + +func main() { + _ = before(uintptr(setup())) + after() +} -- cgit v1.3 From afb5fca25a6f59e9045317727f6899a58471d5f0 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Sun, 13 Sep 2020 13:22:42 +0700 Subject: test: fix flaky test for issue24491 runtime.GC() doesn't guarantee the finalizer has run, so use a channel instead to make sure finalizer was run in call to "after()". Fixes #41361 Change-Id: I69c801e29aea49757ea72c52e8db13239de19ddc Reviewed-on: https://go-review.googlesource.com/c/go/+/254401 Run-TryBot: Cuong Manh Le TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky Trust: Cuong Manh Le --- test/fixedbugs/issue24491b.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'test/fixedbugs') diff --git a/test/fixedbugs/issue24491b.go b/test/fixedbugs/issue24491b.go index 5f4a2f233e..142d798500 100644 --- a/test/fixedbugs/issue24491b.go +++ b/test/fixedbugs/issue24491b.go @@ -11,15 +11,14 @@ package main import ( "runtime" - "sync/atomic" "unsafe" ) -var done uint32 +var done = make(chan bool) func setup() unsafe.Pointer { s := "ok" - runtime.SetFinalizer(&s, func(p *string) { atomic.StoreUint32(&done, 1) }) + runtime.SetFinalizer(&s, func(p *string) { close(done) }) return unsafe.Pointer(&s) } @@ -27,17 +26,18 @@ func setup() unsafe.Pointer { //go:uintptrescapes func before(p uintptr) int { runtime.GC() - if atomic.LoadUint32(&done) != 0 { + select { + case <-done: panic("GC early") + default: } return 0 } func after() int { runtime.GC() - if atomic.LoadUint32(&done) == 0 { - panic("GC late") - } + runtime.GC() + <-done return 0 } -- cgit v1.3 From 42b023d7b9cb8229e3035fa3d36bce41a1ef0c43 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 26 Aug 2020 14:17:35 -0700 Subject: cmd/cgo: use go:notinheap for anonymous structs They can't reasonably be allocated on the heap. Not a huge deal, but it has an interesting and useful side effect. After CL 249917, the compiler and runtime treat pointers to go:notinheap types as uintptrs instead of real pointers (no write barrier, not processed during stack scanning, ...). That feature is exactly what we want for cgo to fix #40954. All the cases we have of pointers declared in C, but which might actually be filled with non-pointer data, are of this form (JNI's jobject heirarch, Darwin's CFType heirarchy, ...). Fixes #40954 Change-Id: I44a3b9bc2513d4287107e39d0cbbd0efd46a3aae Reviewed-on: https://go-review.googlesource.com/c/go/+/250940 Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot Trust: Keith Randall Reviewed-by: Ian Lance Taylor --- src/cmd/cgo/gcc.go | 15 +++++++++++++++ src/cmd/cgo/main.go | 3 ++- src/cmd/cgo/out.go | 3 +++ test/fixedbugs/issue40954.go | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue40954.go (limited to 'test/fixedbugs') diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index eb6c1a5c89..730db44990 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -2448,6 +2448,18 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ tt := *t tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}} tt.Go = c.Ident("struct{}") + if dt.Kind == "struct" { + // We don't know what the representation of this struct is, so don't let + // anyone allocate one on the Go side. As a side effect of this annotation, + // pointers to this type will not be considered pointers in Go. They won't + // get writebarrier-ed or adjusted during a stack copy. This should handle + // all the cases badPointerTypedef used to handle, but hopefully will + // continue to work going forward without any more need for cgo changes. + tt.NotInHeap = true + // TODO: we should probably do the same for unions. Unions can't live + // on the Go heap, right? It currently doesn't work for unions because + // they are defined as a type alias for struct{}, not a defined type. + } typedef[name.Name] = &tt break } @@ -2518,6 +2530,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ } t.Go = name t.BadPointer = sub.BadPointer + t.NotInHeap = sub.NotInHeap if unionWithPointer[sub.Go] { unionWithPointer[t.Go] = true } @@ -2528,6 +2541,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ tt := *t tt.Go = sub.Go tt.BadPointer = sub.BadPointer + tt.NotInHeap = sub.NotInHeap typedef[name.Name] = &tt } @@ -3026,6 +3040,7 @@ func (c *typeConv) anonymousStructTypedef(dt *dwarf.TypedefType) bool { // non-pointers in this type. // TODO: Currently our best solution is to find these manually and list them as // they come up. A better solution is desired. +// Note: DEPRECATED. There is now a better solution. Search for NotInHeap in this file. func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool { if c.badCFType(dt) { return true diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index 5a7bb3f87b..ef3ed968e4 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -151,7 +151,8 @@ type Type struct { Go ast.Expr EnumValues map[string]int64 Typedef string - BadPointer bool + BadPointer bool // this pointer type should be represented as a uintptr (deprecated) + NotInHeap bool // this type should have a go:notinheap annotation } // A FuncType collects information about a function type in both the C and Go worlds. diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 50d2811f1b..03b8333b10 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -108,6 +108,9 @@ func (p *Package) writeDefs() { sort.Strings(typedefNames) for _, name := range typedefNames { def := typedef[name] + if def.NotInHeap { + fmt.Fprintf(fgo2, "//go:notinheap\n") + } fmt.Fprintf(fgo2, "type %s ", name) // We don't have source info for these types, so write them out without source info. // Otherwise types would look like: diff --git a/test/fixedbugs/issue40954.go b/test/fixedbugs/issue40954.go new file mode 100644 index 0000000000..53e9ccf387 --- /dev/null +++ b/test/fixedbugs/issue40954.go @@ -0,0 +1,35 @@ +// run + +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "unsafe" +) + +//go:notinheap +type S struct{ x int } + +func main() { + var i int + p := (*S)(unsafe.Pointer(uintptr(unsafe.Pointer(&i)))) + v := uintptr(unsafe.Pointer(p)) + // p is a pointer to a go:notinheap type. Like some C libraries, + // we stored an integer in that pointer. That integer just happens + // to be the address of i. + // v is also the address of i. + // p has a base type which is marked go:notinheap, so it + // should not be adjusted when the stack is copied. + recurse(100, p, v) +} +func recurse(n int, p *S, v uintptr) { + if n > 0 { + recurse(n-1, p, v) + } + if uintptr(unsafe.Pointer(p)) != v { + panic("adjusted notinheap pointer") + } +} -- cgit v1.3 From ddd35f8d71120b0d0508dd0d8f3a727ba681dfb3 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 17 Sep 2020 21:38:42 -0700 Subject: cmd/compile: more comprehensive tests for #24991 The revised test now checks that unsafe-uintptr correctly works for variadic uintptr parameters too, and the CL corrects the code so this code compiles again. The pointers are still not kept alive properly. That will be fixed by a followup CL. But this CL at least allows programs not affected by that to build again. Updates #24991. Updates #41460. Change-Id: If4c39167b6055e602213fb7522c4f527c43ebda9 Reviewed-on: https://go-review.googlesource.com/c/go/+/255877 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Cuong Manh Le TryBot-Result: Go Bot --- src/cmd/compile/internal/gc/syntax.go | 2 +- src/cmd/compile/internal/gc/walk.go | 1 + test/fixedbugs/issue24491a.go | 26 ++++++++++++++++++++------ 3 files changed, 22 insertions(+), 7 deletions(-) (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index 14d2710da4..4aa2e230ce 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -716,7 +716,7 @@ const ( ODCLCONST // const pi = 3.14 ODCLTYPE // type Int int or type Int = int - ODELETE // delete(Left, Right) + ODELETE // delete(List) 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) diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 2db352c8d5..933f16d9a0 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -3900,6 +3900,7 @@ func wrapCall(n *Node, init *Nodes) *Node { if !isBuiltinCall { call.Op = OCALL call.Left = n.Left + call.SetIsDDD(n.IsDDD()) } call.List.Set(args) fn.Nbody.Set1(call) diff --git a/test/fixedbugs/issue24491a.go b/test/fixedbugs/issue24491a.go index 148134d187..3c595798b5 100644 --- a/test/fixedbugs/issue24491a.go +++ b/test/fixedbugs/issue24491a.go @@ -23,29 +23,43 @@ func setup() unsafe.Pointer { //go:noinline //go:uintptrescapes -func test(s string, p uintptr) int { +func test(s string, p, q uintptr, rest ...uintptr) int { runtime.GC() + runtime.GC() + if *(*string)(unsafe.Pointer(p)) != "ok" { - panic(s + " return unexpected result") + panic(s + ": p failed") + } + if *(*string)(unsafe.Pointer(q)) != "ok" { + panic(s + ": q failed") } + for _, r := range rest { + // TODO(mdempsky): Remove. + break + + if *(*string)(unsafe.Pointer(r)) != "ok" { + panic(s + ": r[i] failed") + } + } + done <- true return 0 } //go:noinline func f() int { - return test("return", uintptr(setup())) + return test("return", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) } func main() { - test("normal", uintptr(setup())) + test("normal", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) <-done - go test("go", uintptr(setup())) + go test("go", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) <-done func() { - defer test("defer", uintptr(setup())) + defer test("defer", uintptr(setup()), uintptr(setup()), uintptr(setup()), uintptr(setup())) }() <-done -- cgit v1.3 From df73945fd2fa0b7c168a042e87e648fdfdfc2c70 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 17 Sep 2020 07:54:01 +0700 Subject: cmd/compile: make error message involving variadic calls clearer Fixes #41440 Change-Id: I2fbac72ae3b76bca32cdeaee678a19af3595d116 Reviewed-on: https://go-review.googlesource.com/c/go/+/255241 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/typecheck.go | 20 ++++++++++++-------- test/fixedbugs/issue41440.go | 14 ++++++++++++++ test/fixedbugs/issue6750.go | 2 +- 3 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 test/fixedbugs/issue41440.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index cbfaa3073e..2654177c25 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -2717,7 +2717,7 @@ func errorDetails(nl Nodes, tstruct *types.Type, isddd bool) string { // sigrepr is a type's representation to the outside world, // in string representations of return signatures // e.g in error messages about wrong arguments to return. -func sigrepr(t *types.Type) string { +func sigrepr(t *types.Type, isddd bool) string { switch t { case types.Idealstring: return "string" @@ -2732,6 +2732,13 @@ func sigrepr(t *types.Type) string { return "number" } + // Turn []T... argument to ...T for clearer error message. + if isddd { + if !t.IsSlice() { + Fatalf("bad type for ... argument: %v", t) + } + return "..." + t.Elem().String() + } return t.String() } @@ -2742,15 +2749,12 @@ func (nl Nodes) sigerr(isddd bool) string { } var typeStrings []string - for _, n := range nl.Slice() { - typeStrings = append(typeStrings, sigrepr(n.Type)) + for i, n := range nl.Slice() { + isdddArg := isddd && i == nl.Len()-1 + typeStrings = append(typeStrings, sigrepr(n.Type, isdddArg)) } - ddd := "" - if isddd { - ddd = "..." - } - return fmt.Sprintf("(%s%s)", strings.Join(typeStrings, ", "), ddd) + return fmt.Sprintf("(%s)", strings.Join(typeStrings, ", ")) } // type check composite diff --git a/test/fixedbugs/issue41440.go b/test/fixedbugs/issue41440.go new file mode 100644 index 0000000000..2b441db803 --- /dev/null +++ b/test/fixedbugs/issue41440.go @@ -0,0 +1,14 @@ +// errorcheck + +// Copyright 2020 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 p + +func f(...int) {} + +func g() { + var x []int + f(x, x...) // ERROR "have \(\[\]int, \.\.\.int\)" +} diff --git a/test/fixedbugs/issue6750.go b/test/fixedbugs/issue6750.go index dbbb454435..f62a85009c 100644 --- a/test/fixedbugs/issue6750.go +++ b/test/fixedbugs/issue6750.go @@ -18,5 +18,5 @@ func printmany(nums ...int) { func main() { printmany(1, 2, 3) printmany([]int{1, 2, 3}...) - printmany(1, "abc", []int{2, 3}...) // ERROR "too many arguments in call to printmany\n\thave \(number, string, \[\]int\.\.\.\)\n\twant \(...int\)" + printmany(1, "abc", []int{2, 3}...) // ERROR "too many arguments in call to printmany\n\thave \(number, string, \.\.\.int\)\n\twant \(...int\)" } -- cgit v1.3 From 23573d0ea225d4b93ccd2b946b1de121c3a6cee5 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Mon, 21 Sep 2020 12:00:24 +0700 Subject: cmd/compile: clearer error when non-bool used as "||" and "&&" operand Fixes #41500 Change-Id: I658d8921b7769b6e4288ca781cbdca5ff14a84ee Reviewed-on: https://go-review.googlesource.com/c/go/+/255899 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/typecheck.go | 16 ++++++++++++++++ test/fixedbugs/issue41500.go | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 test/fixedbugs/issue41500.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 12c99bf48f..2c445567de 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -630,6 +630,22 @@ func typecheck1(n *Node, top int) (res *Node) { break } + // For "x == x && len(s)", it's better to report that "len(s)" (type int) + // can't be used with "&&" than to report that "x == x" (type untyped bool) + // can't be converted to int (see issue #41500). + if n.Op == OANDAND || n.Op == OOROR { + if !n.Left.Type.IsBoolean() { + yyerror("invalid operation: %v (operator %v not defined on %s)", n, n.Op, typekind(n.Left.Type)) + n.Type = nil + return n + } + if !n.Right.Type.IsBoolean() { + yyerror("invalid operation: %v (operator %v not defined on %s)", n, n.Op, typekind(n.Right.Type)) + n.Type = nil + return n + } + } + // ideal mixed with non-ideal l, r = defaultlit2(l, r, false) diff --git a/test/fixedbugs/issue41500.go b/test/fixedbugs/issue41500.go new file mode 100644 index 0000000000..d1e4efc8fd --- /dev/null +++ b/test/fixedbugs/issue41500.go @@ -0,0 +1,20 @@ +// errorcheck + +// Copyright 2020 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 p + +type s struct { + slice []int +} + +func f() { + var x *s + + _ = x == nil || len(x.slice) // ERROR "invalid operation: .+ \(operator \|\| not defined on int\)" + _ = len(x.slice) || x == nil // ERROR "invalid operation: .+ \(operator \|\| not defined on int\)" + _ = x == nil && len(x.slice) // ERROR "invalid operation: .+ \(operator && not defined on int\)" + _ = len(x.slice) && x == nil // ERROR "invalid operation: .+ \(operator && not defined on int\)" +} -- cgit v1.3 From 2333c6299f340a5f76a73a4fec6db23ffa388e97 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 24 Sep 2020 19:26:33 -0700 Subject: runtime: use old capacity to decide on append growth regime We grow the backing store on append by 2x for small sizes and 1.25x for large sizes. The threshold we use for picking the growth factor used to depend on the old length, not the old capacity. That's kind of unfortunate, because then doing append(s, 0, 0) and append(append(s, 0), 0) do different things. (If s has one more spot available, then the former expression chooses its growth based on len(s) and the latter on len(s)+1.) If we instead use the old capacity, we get more consistent behavior. (Both expressions use len(s)+1 == cap(s) to decide.) Fixes #41239 Change-Id: I40686471d256edd72ec92aef973a89b52e235d4b Reviewed-on: https://go-review.googlesource.com/c/go/+/257338 Trust: Keith Randall Trust: Josh Bleecher Snyder Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Josh Bleecher Snyder --- src/runtime/slice.go | 2 +- test/fixedbugs/issue41239.go | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue41239.go (limited to 'test/fixedbugs') diff --git a/src/runtime/slice.go b/src/runtime/slice.go index 82a45c78a9..c0647d95a0 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -146,7 +146,7 @@ func growslice(et *_type, old slice, cap int) slice { if cap > doublecap { newcap = cap } else { - if old.len < 1024 { + if old.cap < 1024 { newcap = doublecap } else { // Check 0 < newcap to detect overflow diff --git a/test/fixedbugs/issue41239.go b/test/fixedbugs/issue41239.go new file mode 100644 index 0000000000..3e9ef5eb66 --- /dev/null +++ b/test/fixedbugs/issue41239.go @@ -0,0 +1,19 @@ +// run + +// Copyright 2020 The Go Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in +// the LICENSE file. + +package main + +import "fmt" + +func main() { + const N = 1024 + var a [N]int + x := cap(append(a[:N-1:N], 9, 9)) + y := cap(append(a[:N:N], 9)) + if x != y { + panic(fmt.Sprintf("different capacity on append: %d vs %d", x, y)) + } +} -- cgit v1.3 From e572218d1273bf54bf8cafd39f93f22de196dd55 Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Sat, 26 Sep 2020 09:42:59 +0200 Subject: cmd/compile: fix escape reason for MAKESLICE with no cap When explaining why the slice from a make() call escapes for the -m -m message, we print "non-const size" if any one of Isconst(n.Left) and Isconst(n.Right) return false; but for OMAKESLICE nodes with no cap, n.Right is nil, so Isconst(n.Right, CTINT) will be always false. Only call Isconst on n.Right if it's not nil. Fixes #41635 Change-Id: I8729801a9b234b68ae40adad64d66fa7653adf09 Reviewed-on: https://go-review.googlesource.com/c/go/+/257641 Reviewed-by: Cuong Manh Le Reviewed-by: Keith Randall Trust: Alberto Donizetti --- src/cmd/compile/internal/gc/escape.go | 2 +- test/fixedbugs/issue41635.go | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue41635.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/escape.go b/src/cmd/compile/internal/gc/escape.go index f435d8ff6a..d79d32ec48 100644 --- a/src/cmd/compile/internal/gc/escape.go +++ b/src/cmd/compile/internal/gc/escape.go @@ -1053,7 +1053,7 @@ func (e *Escape) newLoc(n *Node, transient bool) *EscLocation { if mustHeapAlloc(n) { why := "too large for stack" - if n.Op == OMAKESLICE && (!Isconst(n.Left, CTINT) || !Isconst(n.Right, CTINT)) { + if n.Op == OMAKESLICE && (!Isconst(n.Left, CTINT) || (n.Right != nil && !Isconst(n.Right, CTINT))) { why = "non-constant size" } e.flow(e.heapHole().addr(n, why), loc) diff --git a/test/fixedbugs/issue41635.go b/test/fixedbugs/issue41635.go new file mode 100644 index 0000000000..b33c1a07e7 --- /dev/null +++ b/test/fixedbugs/issue41635.go @@ -0,0 +1,18 @@ +//errorcheck -0 -m -m + +// Copyright 2020 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 p + +func f() { // ERROR "" + b1 := make([]byte, 1<<17) // ERROR "too large for stack" "" + b2 := make([]byte, 100, 1<<17) // ERROR "too large for stack" "" + + n, m := 100, 200 + b1 = make([]byte, n) // ERROR "non-constant size" "" + b2 = make([]byte, 100, m) // ERROR "non-constant size" "" + + _, _ = b1, b2 +} -- cgit v1.3 From ad0ab812f8b80416c92ed227974e3194e98f4cdc Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 28 Sep 2020 12:19:56 -0700 Subject: cmd/compile: fix type checking of "make" arguments As part of type checking make's arguments, we were converting untyped float and complex constant arguments to integers. However, we were doing this without concern for whether the argument was a declared constant. Thus a call like "make([]T, n)" could change n from an untyped float or untyped complex to an untyped integer. The fix here is to simply change checkmake to not call SetVal, which will be handled by defaultlit anyway. However, we also need to properly return the defaultlit result value to the caller, so checkmake's *Node parameter is also changed to **Node. Fixes #41680. Change-Id: I858927a052f384ec38684570d37b10a6906961f7 Reviewed-on: https://go-review.googlesource.com/c/go/+/257966 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Cuong Manh Le TryBot-Result: Go Bot --- src/cmd/compile/internal/gc/typecheck.go | 16 +++++++++------- test/fixedbugs/issue41680.go | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 test/fixedbugs/issue41680.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 8e87fc9df0..0eb0dae373 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -1770,7 +1770,7 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = nil return n } - if !checkmake(t, "len", l) || r != nil && !checkmake(t, "cap", r) { + if !checkmake(t, "len", &l) || r != nil && !checkmake(t, "cap", &r) { n.Type = nil return n } @@ -1794,7 +1794,7 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = nil return n } - if !checkmake(t, "size", l) { + if !checkmake(t, "size", &l) { n.Type = nil return n } @@ -1815,7 +1815,7 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = nil return n } - if !checkmake(t, "buffer", l) { + if !checkmake(t, "buffer", &l) { n.Type = nil return n } @@ -3729,7 +3729,8 @@ ret: n.SetWalkdef(1) } -func checkmake(t *types.Type, arg string, n *Node) bool { +func checkmake(t *types.Type, arg string, np **Node) bool { + n := *np if !n.Type.IsInteger() && n.Type.Etype != TIDEAL { yyerror("non-integer %s argument in make(%v) - %v", arg, t, n.Type) return false @@ -3739,12 +3740,12 @@ func checkmake(t *types.Type, arg string, n *Node) bool { // to avoid redundant "constant NNN overflows int" errors. switch consttype(n) { case CTINT, CTRUNE, CTFLT, CTCPLX: - n.SetVal(toint(n.Val())) - if n.Val().U.(*Mpint).CmpInt64(0) < 0 { + v := toint(n.Val()).U.(*Mpint) + if v.CmpInt64(0) < 0 { yyerror("negative %s argument in make(%v)", arg, t) return false } - if n.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 { + if v.Cmp(maxintval[TINT]) > 0 { yyerror("%s argument too large in make(%v)", arg, t) return false } @@ -3756,6 +3757,7 @@ func checkmake(t *types.Type, arg string, n *Node) bool { // for instance, indexlit might be called here and incorporate some // of the bounds checks done for make. n = defaultlit(n, types.Types[TINT]) + *np = n return true } diff --git a/test/fixedbugs/issue41680.go b/test/fixedbugs/issue41680.go new file mode 100644 index 0000000000..9dfeb7d503 --- /dev/null +++ b/test/fixedbugs/issue41680.go @@ -0,0 +1,21 @@ +// compile + +// Copyright 2020 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 p + +func F(s string) bool { + const m = 16 + const n = 1e5 + _ = make([]int, n) + return len(s) < n*m +} + +func G() { + const n = 1e5 + _ = make([]int, n) + f := n + var _ float64 = f +} -- cgit v1.3 From 0e85fd7561de869add933801c531bf25dee9561c Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 29 Sep 2020 02:11:10 -0700 Subject: cmd/compile: report type loop for invalid recursive types Similar to how we report initialization loops in initorder.go and type alias loops in typecheck.go, this CL updates align.go to warn about invalid recursive types. The code is based on the loop code from initorder.go, with minimal changes to adapt from detecting variable/function initialization loops to detecting type declaration loops. Thanks to Cuong Manh Le for investigating this, helping come up with test cases, and exploring solutions. Fixes #41575 Updates #41669. Change-Id: Idb2cb8c5e1d645e62900e178fcb50af33e1700a1 Reviewed-on: https://go-review.googlesource.com/c/go/+/258177 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Robert Griesemer Reviewed-by: Cuong Manh Le Trust: Matthew Dempsky Trust: Cuong Manh Le --- src/cmd/compile/internal/gc/align.go | 98 ++++++++++++++++++++++++++++++++---- src/cmd/compile/internal/gc/subr.go | 10 ++++ test/fixedbugs/bug195.go | 16 +++--- test/fixedbugs/issue22904.go | 4 +- test/fixedbugs/issue23823.go | 3 +- test/fixedbugs/issue41575.go | 36 +++++++++++++ 6 files changed, 147 insertions(+), 20 deletions(-) create mode 100644 test/fixedbugs/issue41575.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go index ab578ee8c7..5af403afa3 100644 --- a/src/cmd/compile/internal/gc/align.go +++ b/src/cmd/compile/internal/gc/align.go @@ -5,7 +5,9 @@ package gc import ( + "bytes" "cmd/compile/internal/types" + "fmt" "sort" ) @@ -173,6 +175,91 @@ func widstruct(errtype *types.Type, t *types.Type, o int64, flag int) int64 { return o } +// findTypeLoop searches for an invalid type declaration loop involving +// type t and reports whether one is found. If so, path contains the +// loop. +// +// path points to a slice used for tracking the sequence of types +// visited. Using a pointer to a slice allows the slice capacity to +// grow and limit reallocations. +func findTypeLoop(t *types.Type, path *[]*types.Type) bool { + // We implement a simple DFS loop-finding algorithm. This + // could be faster, but type cycles are rare. + + if t.Sym != nil { + // Declared type. Check for loops and otherwise + // recurse on the type expression used in the type + // declaration. + + for i, x := range *path { + if x == t { + *path = (*path)[i:] + return true + } + } + + *path = append(*path, t) + if findTypeLoop(asNode(t.Nod).Name.Param.Ntype.Type, path) { + return true + } + *path = (*path)[:len(*path)-1] + } else { + // Anonymous type. Recurse on contained types. + + switch t.Etype { + case TARRAY: + if findTypeLoop(t.Elem(), path) { + return true + } + case TSTRUCT: + for _, f := range t.Fields().Slice() { + if findTypeLoop(f.Type, path) { + return true + } + } + case TINTER: + for _, m := range t.Methods().Slice() { + if m.Type.IsInterface() { // embedded interface + if findTypeLoop(m.Type, path) { + return true + } + } + } + } + } + + return false +} + +func reportTypeLoop(t *types.Type) { + if t.Broke() { + return + } + + var l []*types.Type + if !findTypeLoop(t, &l) { + Fatalf("failed to find type loop for: %v", t) + } + + // Rotate loop so that the earliest type declaration is first. + i := 0 + for j, t := range l[1:] { + if typePos(t).Before(typePos(l[i])) { + i = j + 1 + } + } + l = append(l[i:], l[:i]...) + + var msg bytes.Buffer + fmt.Fprintf(&msg, "invalid recursive type %v\n", l[0]) + for _, t := range l { + fmt.Fprintf(&msg, "\t%v: %v refers to\n", linestr(typePos(t)), t) + t.SetBroke(true) + } + fmt.Fprintf(&msg, "\t%v: %v", linestr(typePos(l[0])), l[0]) + yyerrorl(typePos(l[0]), msg.String()) +} + // dowidth calculates and stores the size and alignment for t. // If sizeCalculationDisabled is set, and the size/alignment // have not already been calculated, it calls Fatal. @@ -192,11 +279,7 @@ func dowidth(t *types.Type) { } if t.Width == -2 { - if !t.Broke() { - t.SetBroke(true) - yyerrorl(asNode(t.Nod).Pos, "invalid recursive type %v", t) - } - + reportTypeLoop(t) t.Width = 0 t.Align = 1 return @@ -308,10 +391,7 @@ func dowidth(t *types.Type) { checkwidth(t.Key()) case TFORW: // should have been filled in - if !t.Broke() { - t.SetBroke(true) - yyerror("invalid recursive type %v", t) - } + reportTypeLoop(t) w = 1 // anything will do case TANY: diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index b5527e2f83..07547df36e 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -1921,3 +1921,13 @@ func ifaceData(pos src.XPos, n *Node, t *types.Type) *Node { ind.SetBounded(true) return ind } + +// typePos returns the position associated with t. +// This is where t was declared or where it appeared as a type expression. +func typePos(t *types.Type) src.XPos { + n := asNode(t.Nod) + if n == nil || !n.Pos.IsKnown() { + Fatalf("bad type: %v", t) + } + return n.Pos +} diff --git a/test/fixedbugs/bug195.go b/test/fixedbugs/bug195.go index 496c0be610..aef7bd2d89 100644 --- a/test/fixedbugs/bug195.go +++ b/test/fixedbugs/bug195.go @@ -6,22 +6,22 @@ package main -type I1 interface { I2 } // ERROR "interface" +type I1 interface{ I2 } // ERROR "interface" type I2 int -type I3 interface { int } // ERROR "interface" +type I3 interface{ int } // ERROR "interface" type S struct { - x interface{ S } // ERROR "interface" + x interface{ S } // ERROR "interface" } -type I4 interface { // GC_ERROR "invalid recursive type" - I4 // GCCGO_ERROR "interface" +type I4 interface { // GC_ERROR "invalid recursive type I4\n\tLINE: I4 refers to\n\tLINE: I4$" + I4 // GCCGO_ERROR "interface" } -type I5 interface { // GC_ERROR "invalid recursive type" - I6 // GCCGO_ERROR "interface" +type I5 interface { // GC_ERROR "invalid recursive type I5\n\tLINE: I5 refers to\n\tLINE+4: I6 refers to\n\tLINE: I5$" + I6 // GCCGO_ERROR "interface" } type I6 interface { - I5 // GCCGO_ERROR "interface" + I5 // GCCGO_ERROR "interface" } diff --git a/test/fixedbugs/issue22904.go b/test/fixedbugs/issue22904.go index 46cb7c048a..09f4a2118e 100644 --- a/test/fixedbugs/issue22904.go +++ b/test/fixedbugs/issue22904.go @@ -9,8 +9,8 @@ package p -type a struct{ b } -type b struct{ a } // ERROR "invalid recursive type" +type a struct{ b } // ERROR "invalid recursive type" +type b struct{ a } var x interface{} diff --git a/test/fixedbugs/issue23823.go b/test/fixedbugs/issue23823.go index 2f802d0988..fe6cef1fb4 100644 --- a/test/fixedbugs/issue23823.go +++ b/test/fixedbugs/issue23823.go @@ -10,6 +10,7 @@ type I1 = interface { I2 } -type I2 interface { // ERROR "invalid recursive type" +// BAD: type loop should mention I1; see also #41669 +type I2 interface { // ERROR "invalid recursive type I2\n\tLINE: I2 refers to\n\tLINE: I2$" I1 } diff --git a/test/fixedbugs/issue41575.go b/test/fixedbugs/issue41575.go new file mode 100644 index 0000000000..d03d1c8b3e --- /dev/null +++ b/test/fixedbugs/issue41575.go @@ -0,0 +1,36 @@ +// errorcheck + +// Copyright 2020 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 p + +type T1 struct { // ERROR "invalid recursive type T1\n\tLINE: T1 refers to\n\tLINE+4: T2 refers to\n\tLINE: T1$" + f2 T2 +} + +type T2 struct { + f1 T1 +} + +type a b +type b c // ERROR "invalid recursive type b\n\tLINE: b refers to\n\tLINE+1: c refers to\n\tLINE: b$" +type c b + +type d e +type e f +type f f // ERROR "invalid recursive type f\n\tLINE: f refers to\n\tLINE: f$" + +type g struct { // ERROR "invalid recursive type g\n\tLINE: g refers to\n\tLINE: g$" + h struct { + g + } +} + +type w x +type x y // ERROR "invalid recursive type x\n\tLINE: x refers to\n\tLINE+1: y refers to\n\tLINE+2: z refers to\n\tLINE: x$" +type y struct{ z } +type z [10]x + +type w2 w // refer to the type loop again -- cgit v1.3 From 095e0f48a19fa3bd7901f79420374b9cb50940e9 Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Thu, 1 Oct 2020 12:03:27 +0200 Subject: cmd/compile: change mustHeapAlloc to return a reason why This change renames mustHeapAlloc to heapAllocReason, and changes it to return the reason why the argument must escape, so we don't have to re-deduce it in its callers just to print the escape reason. It also embeds isSmallMakeSlice body in heapAllocReason, since the former was only used by the latter, and deletes isSmallMakeSlice. An outdated TODO to remove smallintconst, which the TODO claimed was only used in one place, was also removed, since grepping shows we currently call smallintconst in 11 different places. Change-Id: I0bd11bf29b92c4126f5bb455877ff73217d5a155 Reviewed-on: https://go-review.googlesource.com/c/go/+/258678 Run-TryBot: Alberto Donizetti TryBot-Result: Go Bot Trust: Alberto Donizetti Trust: Cuong Manh Le Reviewed-by: Cuong Manh Le Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/const.go | 1 - src/cmd/compile/internal/gc/esc.go | 31 +++++++++++++++++++++---------- src/cmd/compile/internal/gc/escape.go | 6 +----- src/cmd/compile/internal/gc/walk.go | 17 ++--------------- test/fixedbugs/issue41635.go | 11 +++++------ 5 files changed, 29 insertions(+), 37 deletions(-) (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go index c0ed8192d9..d881be485e 100644 --- a/src/cmd/compile/internal/gc/const.go +++ b/src/cmd/compile/internal/gc/const.go @@ -1134,7 +1134,6 @@ func strlit(n *Node) string { return n.Val().U.(string) } -// TODO(gri) smallintconst is only used in one place - can we used indexconst? func smallintconst(n *Node) bool { if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil { switch simtype[n.Type.Etype] { diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index 375331d1f5..d7aa72b450 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -169,36 +169,47 @@ func mayAffectMemory(n *Node) bool { } } -func mustHeapAlloc(n *Node) bool { +// heapAllocReason returns the reason the given Node must be heap +// allocated, or the empty string if it doesn't. +func heapAllocReason(n *Node) string { if n.Type == nil { - return false + return "" } // Parameters are always passed via the stack. if n.Op == ONAME && (n.Class() == PPARAM || n.Class() == PPARAMOUT) { - return false + return "" } if n.Type.Width > maxStackVarSize { - return true + return "too large for stack" } if (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= maxImplicitStackVarSize { - return true + return "too large for stack" } if n.Op == OCLOSURE && closureType(n).Size() >= maxImplicitStackVarSize { - return true + return "too large for stack" } if n.Op == OCALLPART && partialCallType(n).Size() >= maxImplicitStackVarSize { - return true + return "too large for stack" } - if n.Op == OMAKESLICE && !isSmallMakeSlice(n) { - return true + if n.Op == OMAKESLICE { + r := n.Right + if r == nil { + r = n.Left + } + if !smallintconst(r) { + return "non-constant size" + } + if t := n.Type; t.Elem().Width != 0 && r.Int64() >= maxImplicitStackVarSize/t.Elem().Width { + return "too large for stack" + } } - return false + return "" } // addrescapes tags node n as having had its address taken diff --git a/src/cmd/compile/internal/gc/escape.go b/src/cmd/compile/internal/gc/escape.go index d79d32ec48..79df584ab1 100644 --- a/src/cmd/compile/internal/gc/escape.go +++ b/src/cmd/compile/internal/gc/escape.go @@ -1051,11 +1051,7 @@ func (e *Escape) newLoc(n *Node, transient bool) *EscLocation { } n.SetOpt(loc) - if mustHeapAlloc(n) { - why := "too large for stack" - if n.Op == OMAKESLICE && (!Isconst(n.Left, CTINT) || (n.Right != nil && !Isconst(n.Right, CTINT))) { - why = "non-constant size" - } + if why := heapAllocReason(n); why != "" { e.flow(e.heapHole().addr(n, why), loc) } } diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 8e45059eab..3fe7c3e089 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -336,19 +336,6 @@ func walkstmt(n *Node) *Node { return n } -func isSmallMakeSlice(n *Node) bool { - if n.Op != OMAKESLICE { - return false - } - r := n.Right - if r == nil { - r = n.Left - } - t := n.Type - - return smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < maxImplicitStackVarSize/t.Elem().Width) -} - // walk the whole tree of the body of an // expression or simple statement. // the types expressions are calculated. @@ -1339,8 +1326,8 @@ opswitch: yyerror("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem()) } if n.Esc == EscNone { - if !isSmallMakeSlice(n) { - Fatalf("non-small OMAKESLICE with EscNone: %v", n) + if why := heapAllocReason(n); why != "" { + Fatalf("%v has EscNone, but %v", n, why) } // var arr [r]T // n = arr[:l] diff --git a/test/fixedbugs/issue41635.go b/test/fixedbugs/issue41635.go index b33c1a07e7..35c0034cdd 100644 --- a/test/fixedbugs/issue41635.go +++ b/test/fixedbugs/issue41635.go @@ -7,12 +7,11 @@ package p func f() { // ERROR "" - b1 := make([]byte, 1<<17) // ERROR "too large for stack" "" - b2 := make([]byte, 100, 1<<17) // ERROR "too large for stack" "" - n, m := 100, 200 - b1 = make([]byte, n) // ERROR "non-constant size" "" - b2 = make([]byte, 100, m) // ERROR "non-constant size" "" + _ = make([]byte, 1<<17) // ERROR "too large for stack" "" + _ = make([]byte, 100, 1<<17) // ERROR "too large for stack" "" + _ = make([]byte, n, 1<<17) // ERROR "too large for stack" "" - _, _ = b1, b2 + _ = make([]byte, n) // ERROR "non-constant size" "" + _ = make([]byte, 100, m) // ERROR "non-constant size" "" } -- cgit v1.3 From 694025e74f861bf48a737a8b42612d6397f1879b Mon Sep 17 00:00:00 2001 From: David Chase Date: Mon, 5 Oct 2020 12:07:00 -0400 Subject: cmd/compile: avoid applying ARM CMP->CMN rewrite in unsigned context Fixes #41780. Change-Id: I1dc7c19a9f057650905da3a96214c2ff4abb51be Reviewed-on: https://go-review.googlesource.com/c/go/+/259450 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/gen/ARM.rules | 4 +- src/cmd/compile/internal/ssa/rewriteARM.go | 243 +++++++++++++++++++++++++---- test/fixedbugs/issue41780.go | 39 +++++ 3 files changed, 257 insertions(+), 29 deletions(-) create mode 100644 test/fixedbugs/issue41780.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules index 9490805f46..aad7236d59 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM.rules @@ -1263,8 +1263,8 @@ (SRLconst (SLLconst x [c]) [d]) && objabi.GOARM==7 && uint64(d)>=uint64(c) && uint64(d)<=31 => (BFXU [(d-c)|(32-d)<<8] x) // comparison simplification -(CMP x (RSBconst [0] y)) => (CMN x y) -(CMN x (RSBconst [0] y)) => (CMP x y) +((LT|LE|EQ|NE|GE|GT) (CMP x (RSBconst [0] y))) => ((LT|LE|EQ|NE|GE|GT) (CMN x y)) // sense of carry bit not preserved +((LT|LE|EQ|NE|GE|GT) (CMN x (RSBconst [0] y))) => ((LT|LE|EQ|NE|GE|GT) (CMP x y)) // sense of carry bit not preserved (EQ (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 => (EQ (CMP x y) yes no) (EQ (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 => (EQ (CMP a (MUL x y)) yes no) (EQ (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 => (EQ (CMPconst [c] x) yes no) diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go index 4e44165169..435da688b7 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM.go +++ b/src/cmd/compile/internal/ssa/rewriteARM.go @@ -3362,21 +3362,6 @@ func rewriteValueARM_OpARMCMN(v *Value) bool { } break } - // match: (CMN x (RSBconst [0] y)) - // result: (CMP x y) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - x := v_0 - if v_1.Op != OpARMRSBconst || auxIntToInt32(v_1.AuxInt) != 0 { - continue - } - y := v_1.Args[0] - v.reset(OpARMCMP) - v.AddArg2(x, y) - return true - } - break - } return false } func rewriteValueARM_OpARMCMNconst(v *Value) bool { @@ -3938,18 +3923,6 @@ func rewriteValueARM_OpARMCMP(v *Value) bool { v.AddArg(v0) return true } - // match: (CMP x (RSBconst [0] y)) - // result: (CMN x y) - for { - x := v_0 - if v_1.Op != OpARMRSBconst || auxIntToInt32(v_1.AuxInt) != 0 { - break - } - y := v_1.Args[0] - v.reset(OpARMCMN) - v.AddArg2(x, y) - return true - } return false } func rewriteValueARM_OpARMCMPD(v *Value) bool { @@ -16002,6 +15975,42 @@ func rewriteBlockARM(b *Block) bool { b.resetWithControl(BlockARMEQ, cmp) return true } + // match: (EQ (CMP x (RSBconst [0] y))) + // result: (EQ (CMN x y)) + for b.Controls[0].Op == OpARMCMP { + v_0 := b.Controls[0] + _ = v_0.Args[1] + x := v_0.Args[0] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + break + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMEQ, v0) + return true + } + // match: (EQ (CMN x (RSBconst [0] y))) + // result: (EQ (CMP x y)) + for b.Controls[0].Op == OpARMCMN { + v_0 := b.Controls[0] + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { + x := v_0_0 + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + continue + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMEQ, v0) + return true + } + break + } // match: (EQ (CMPconst [0] l:(SUB x y)) yes no) // cond: l.Uses==1 // result: (EQ (CMP x y) yes no) @@ -16848,6 +16857,42 @@ func rewriteBlockARM(b *Block) bool { b.resetWithControl(BlockARMLE, cmp) return true } + // match: (GE (CMP x (RSBconst [0] y))) + // result: (GE (CMN x y)) + for b.Controls[0].Op == OpARMCMP { + v_0 := b.Controls[0] + _ = v_0.Args[1] + x := v_0.Args[0] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + break + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMGE, v0) + return true + } + // match: (GE (CMN x (RSBconst [0] y))) + // result: (GE (CMP x y)) + for b.Controls[0].Op == OpARMCMN { + v_0 := b.Controls[0] + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { + x := v_0_0 + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + continue + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMGE, v0) + return true + } + break + } // match: (GE (CMPconst [0] l:(SUB x y)) yes no) // cond: l.Uses==1 // result: (GEnoov (CMP x y) yes no) @@ -17728,6 +17773,42 @@ func rewriteBlockARM(b *Block) bool { b.resetWithControl(BlockARMLT, cmp) return true } + // match: (GT (CMP x (RSBconst [0] y))) + // result: (GT (CMN x y)) + for b.Controls[0].Op == OpARMCMP { + v_0 := b.Controls[0] + _ = v_0.Args[1] + x := v_0.Args[0] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + break + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMGT, v0) + return true + } + // match: (GT (CMN x (RSBconst [0] y))) + // result: (GT (CMP x y)) + for b.Controls[0].Op == OpARMCMN { + v_0 := b.Controls[0] + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { + x := v_0_0 + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + continue + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMGT, v0) + return true + } + break + } // match: (GT (CMPconst [0] l:(SUB x y)) yes no) // cond: l.Uses==1 // result: (GTnoov (CMP x y) yes no) @@ -18699,6 +18780,42 @@ func rewriteBlockARM(b *Block) bool { b.resetWithControl(BlockARMGE, cmp) return true } + // match: (LE (CMP x (RSBconst [0] y))) + // result: (LE (CMN x y)) + for b.Controls[0].Op == OpARMCMP { + v_0 := b.Controls[0] + _ = v_0.Args[1] + x := v_0.Args[0] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + break + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMLE, v0) + return true + } + // match: (LE (CMN x (RSBconst [0] y))) + // result: (LE (CMP x y)) + for b.Controls[0].Op == OpARMCMN { + v_0 := b.Controls[0] + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { + x := v_0_0 + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + continue + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMLE, v0) + return true + } + break + } // match: (LE (CMPconst [0] l:(SUB x y)) yes no) // cond: l.Uses==1 // result: (LEnoov (CMP x y) yes no) @@ -19579,6 +19696,42 @@ func rewriteBlockARM(b *Block) bool { b.resetWithControl(BlockARMGT, cmp) return true } + // match: (LT (CMP x (RSBconst [0] y))) + // result: (LT (CMN x y)) + for b.Controls[0].Op == OpARMCMP { + v_0 := b.Controls[0] + _ = v_0.Args[1] + x := v_0.Args[0] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + break + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMLT, v0) + return true + } + // match: (LT (CMN x (RSBconst [0] y))) + // result: (LT (CMP x y)) + for b.Controls[0].Op == OpARMCMN { + v_0 := b.Controls[0] + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { + x := v_0_0 + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + continue + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMLT, v0) + return true + } + break + } // match: (LT (CMPconst [0] l:(SUB x y)) yes no) // cond: l.Uses==1 // result: (LTnoov (CMP x y) yes no) @@ -20609,6 +20762,42 @@ func rewriteBlockARM(b *Block) bool { b.resetWithControl(BlockARMNE, cmp) return true } + // match: (NE (CMP x (RSBconst [0] y))) + // result: (NE (CMN x y)) + for b.Controls[0].Op == OpARMCMP { + v_0 := b.Controls[0] + _ = v_0.Args[1] + x := v_0.Args[0] + v_0_1 := v_0.Args[1] + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + break + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMNE, v0) + return true + } + // match: (NE (CMN x (RSBconst [0] y))) + // result: (NE (CMP x y)) + for b.Controls[0].Op == OpARMCMN { + v_0 := b.Controls[0] + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { + x := v_0_0 + if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 { + continue + } + y := v_0_1.Args[0] + v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg2(x, y) + b.resetWithControl(BlockARMNE, v0) + return true + } + break + } // match: (NE (CMPconst [0] l:(SUB x y)) yes no) // cond: l.Uses==1 // result: (NE (CMP x y) yes no) diff --git a/test/fixedbugs/issue41780.go b/test/fixedbugs/issue41780.go new file mode 100644 index 0000000000..632c144a48 --- /dev/null +++ b/test/fixedbugs/issue41780.go @@ -0,0 +1,39 @@ +// run + +// Copyright 2020 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. + +// Checks that conversion of CMP(x,-y) -> CMN(x,y) is only applied in correct context. + +package main + +type decimal struct { + d [8]byte // digits, big-endian representation + dp int // decimal point +} + +var powtab = []int{1, 3, 6, 9, 13, 16, 19, 23, 26} + +//go:noinline +func foo(d *decimal) int { + exp := int(d.d[1]) + if d.dp < 0 || d.dp == 0 && d.d[0] < '5' { + var n int + if -d.dp >= len(powtab) { + n = 27 + } else { + n = powtab[-d.dp] // incorrect CMP -> CMN substitution causes indexing panic. + } + exp += n + } + return exp +} + +func main() { + var d decimal + d.d[0] = '1' + if foo(&d) != 1 { + println("FAILURE (though not the one this test was written to catch)") + } +} -- cgit v1.3 From f8d80977b784fd4879963e61dc9fca1fc9bf2193 Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 2 Oct 2020 14:53:48 -0400 Subject: cmd/compile: correct leaf type when "selecting" singleton register-sized struct Two part fix: 1) bring the type "correction" forward from a later CL in the expand calls series 2) when a leaf-selwect is rewritten in place, update the type (it might have been changed by the type correction in 1). Fixes #41736. Change-Id: Id097efd10481bf0ad92aaead81a7207221c144b5 Reviewed-on: https://go-review.googlesource.com/c/go/+/259203 Trust: David Chase Run-TryBot: David Chase TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/config.go | 2 +- src/cmd/compile/internal/ssa/expand_calls.go | 41 +++++++++-- test/fixedbugs/issue41736.go | 105 +++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 test/fixedbugs/issue41736.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 649b5ba820..f1a748309c 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -195,7 +195,7 @@ const ( ClassParamOut // return value ) -const go116lateCallExpansion = false +const go116lateCallExpansion = true // LateCallExpansionEnabledWithin returns true if late call expansion should be tested // within compilation of a function/method triggered by GOSSAHASH (defaults to "yes"). diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 7b1d656b64..992936b2d3 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -58,6 +58,29 @@ func expandCalls(f *Func) { return t.IsStruct() || t.IsArray() || regSize == 4 && t.Size() > 4 && t.IsInteger() } + // removeTrivialWrapperTypes unwraps layers of + // struct { singleField SomeType } and [1]SomeType + // until a non-wrapper type is reached. This is useful + // for working with assignments to/from interface data + // fields (either second operand to OpIMake or OpIData) + // where the wrapping or type conversion can be elided + // because of type conversions/assertions in source code + // that do not appear in SSA. + removeTrivialWrapperTypes := func(t *types.Type) *types.Type { + for { + if t.IsStruct() && t.NumFields() == 1 { + t = t.Field(0).Type + continue + } + if t.IsArray() && t.NumElem() == 1 { + t = t.Elem() + continue + } + break + } + return t + } + // Calls that need lowering have some number of inputs, including a memory input, // and produce a tuple of (value1, value2, ..., mem) where valueK may or may not be SSA-able. @@ -84,7 +107,7 @@ func expandCalls(f *Func) { // rewrite v as a Copy of call -- the replacement call will produce a mem. leaf.copyOf(call) } else { - leafType := leaf.Type + leafType := removeTrivialWrapperTypes(leaf.Type) pt := types.NewPtr(leafType) if canSSAType(leafType) { off := f.ConstOffPtrSP(pt, offset+aux.OffsetOfResult(which), sp) @@ -92,6 +115,7 @@ func expandCalls(f *Func) { if leaf.Block == call.Block { leaf.reset(OpLoad) leaf.SetArgs2(off, call) + leaf.Type = leafType } else { w := call.Block.NewValue2(leaf.Pos, OpLoad, leafType, off, call) leaf.copyOf(w) @@ -192,6 +216,13 @@ func expandCalls(f *Func) { case types.TARRAY: elt := t.Elem() + if src.Op == OpIData && t.NumElem() == 1 && t.Width == regSize && elt.Width == regSize { + t = removeTrivialWrapperTypes(t) + if t.Etype == types.TSTRUCT || t.Etype == types.TARRAY { + f.Fatalf("Did not expect to find IDATA-immediate with non-trivial struct/array in it") + } + break // handle the leaf type. + } for i := int64(0); i < t.NumElem(); i++ { sel := src.Block.NewValue1I(pos, OpArraySelect, elt, i, src) mem = splitStore(dst, sel, mem, v, elt, offset+i*elt.Width, firstStorePos) @@ -199,7 +230,7 @@ func expandCalls(f *Func) { } return mem case types.TSTRUCT: - if src.Op == OpIData && t.NumFields() == 1 && t.Field(0).Type.Width == t.Width && t.Width == regSize { + if src.Op == OpIData && t.NumFields() == 1 && t.Field(0).Type.Width == t.Width && t.Width == regSize { // This peculiar test deals with accesses to immediate interface data. // It works okay because everything is the same size. // Example code that triggers this can be found in go/constant/value.go, function ToComplex @@ -207,11 +238,9 @@ func expandCalls(f *Func) { // v121 (+882) = StaticLECall {AuxCall{"".itof([intVal,0])[floatVal,8]}} [16] v119 v1 // This corresponds to the generic rewrite rule "(StructSelect [0] (IData x)) => (IData x)" // Guard against "struct{struct{*foo}}" - for t.Etype == types.TSTRUCT && t.NumFields() == 1 { - t = t.Field(0).Type - } + t = removeTrivialWrapperTypes(t) if t.Etype == types.TSTRUCT || t.Etype == types.TARRAY { - f.Fatalf("Did not expect to find IDATA-immediate with non-trivial struct in it") + f.Fatalf("Did not expect to find IDATA-immediate with non-trivial struct/array in it") } break // handle the leaf type. } diff --git a/test/fixedbugs/issue41736.go b/test/fixedbugs/issue41736.go new file mode 100644 index 0000000000..36f127f4fb --- /dev/null +++ b/test/fixedbugs/issue41736.go @@ -0,0 +1,105 @@ +// compile + +// Copyright 2020 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 p + +type I struct { + x int64 +} + +type F struct { + x float64 +} + +type C struct { + x *complex128 +} + +type D struct { + x complex64 +} + +type A [1]*complex128 + +//go:noinline +func (i I) X() C { + cx := complex(0, float64(i.x)) + return C{&cx} +} + +//go:noinline +func (f F) X() C { + cx := complex(f.x, 0) + return C{&cx} +} + +//go:noinline +func (c C) X() C { + cx := complex(imag(*c.x), real(*c.x)) + return C{&cx} +} + +//go:noinline +func (d D) X() C { + cx := complex(float64(imag(d.x)), -float64(real(d.x))) + return C{&cx} +} + +//go:noinline +func (a A) X() C { + cx := complex(-float64(imag(*a[0])), float64(real(*a[0]))) + return C{&cx} +} + +//go:noinline +func (i I) id() I { + return i +} + +//go:noinline +func (f F) id() F { + return f +} + +//go:noinline +func (c C) id() C { + return c +} + +//go:noinline +func (d D) id() D { + return d +} + +//go:noinline +func (a A) id() A { + return a +} + +type T interface { + X() C +} + +func G(x []T) []T { + var y []T + for _, a := range x { + var v T + switch u := a.(type) { + case I: + v = u.id() + case F: + v = u.id() + case C: + v = u.id() + case D: + v = u.id() + case A: + v = u.id() + } + y = append(y, v) + } + return y +} -- cgit v1.3 From 2e4ceaf963fc2a0ce95a198769012e62ec4e28ae Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Thu, 17 Sep 2020 12:39:43 -0400 Subject: cmd/dist: enable more tests on macOS/ARM64 Unlike iOS, macOS ARM64 is more of a fully featured OS. Enable more tests. Updates #38485. Change-Id: I2e2240c848d21996db2b950a4a6856987f7a652c Reviewed-on: https://go-review.googlesource.com/c/go/+/256919 Trust: Cherry Zhang Reviewed-by: Ian Lance Taylor --- src/cmd/dist/test.go | 2 +- test/fixedbugs/bug429_run.go | 7 ++++++- test/fixedbugs/issue21576.go | 7 ++++++- test/nilptr.go | 3 ++- 4 files changed, 15 insertions(+), 4 deletions(-) (limited to 'test/fixedbugs') diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index da894e3eef..abe496fdee 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -903,7 +903,7 @@ func (t *tester) addCmd(dt *distTest, dir string, cmdline ...interface{}) *exec. } func (t *tester) iOS() bool { - return (goos == "darwin" || goos == "ios") && goarch == "arm64" + return goos == "ios" } func (t *tester) out(v string) { diff --git a/test/fixedbugs/bug429_run.go b/test/fixedbugs/bug429_run.go index c6a02aae5e..60cc5b62de 100644 --- a/test/fixedbugs/bug429_run.go +++ b/test/fixedbugs/bug429_run.go @@ -1,6 +1,11 @@ -// +build !nacl,!js // run +// +build !nacl,!js +// +build !darwin !arm64 + +// Skip on darwin/arm64 as it requires external linking, which brings in +// cgo, causing deadlock detection not working. + // Copyright 2014 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. diff --git a/test/fixedbugs/issue21576.go b/test/fixedbugs/issue21576.go index b7a32f07ac..3797a8c9ba 100644 --- a/test/fixedbugs/issue21576.go +++ b/test/fixedbugs/issue21576.go @@ -1,6 +1,11 @@ -// +build !nacl,!js // run +// +build !nacl,!js +// +build !darwin !arm64 + +// Skip on darwin/arm64 as it requires external linking, which brings in +// cgo, causing deadlock detection not working. + // Copyright 2019 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. diff --git a/test/nilptr.go b/test/nilptr.go index 90f57c54b6..c9a044dd36 100644 --- a/test/nilptr.go +++ b/test/nilptr.go @@ -8,7 +8,8 @@ // in a large address space. // +build !aix -// Address space starts at 1<<32 on AIX, so dummy is too far. +// +build !darwin !arm64 +// Address space starts at 1<<32 on AIX and on darwin/arm64, so dummy is too far. package main -- cgit v1.3 From a4b95cd092aa10b40c6be82a3e0bf1052e27122d Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 8 Oct 2020 11:18:02 -0700 Subject: cmd/compile: fix incorrect comparison folding We lost a sign extension that was necessary. The nonnegative comparison didn't have the correct extension on it. If the larger constant is positive, but its shorter sign extension is negative, the rule breaks. Fixes #41872 Change-Id: I6592ef103f840fbb786bf8cb94fd8804c760c976 Reviewed-on: https://go-review.googlesource.com/c/go/+/260701 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Alberto Donizetti --- src/cmd/compile/internal/ssa/gen/AMD64.rules | 4 ++-- src/cmd/compile/internal/ssa/rewriteAMD64.go | 8 ++++---- test/fixedbugs/issue41872.go | 26 ++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 test/fixedbugs/issue41872.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index 408678f054..8a253035e0 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -1274,8 +1274,8 @@ (CMPQconst (ANDQconst _ [m]) [n]) && 0 <= m && m < n => (FlagLT_ULT) (CMPQconst (ANDLconst _ [m]) [n]) && 0 <= m && m < n => (FlagLT_ULT) (CMPLconst (ANDLconst _ [m]) [n]) && 0 <= m && m < n => (FlagLT_ULT) -(CMPWconst (ANDLconst _ [m]) [n]) && 0 <= m && int16(m) < n => (FlagLT_ULT) -(CMPBconst (ANDLconst _ [m]) [n]) && 0 <= m && int8(m) < n => (FlagLT_ULT) +(CMPWconst (ANDLconst _ [m]) [n]) && 0 <= int16(m) && int16(m) < n => (FlagLT_ULT) +(CMPBconst (ANDLconst _ [m]) [n]) && 0 <= int8(m) && int8(m) < n => (FlagLT_ULT) // TESTQ c c sets flags like CMPQ c 0. (TESTQconst [c] (MOVQconst [d])) && int64(c) == d && c == 0 => (FlagEQ) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 3d7eb8c9a4..32ef26f98d 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -6886,7 +6886,7 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value) bool { return true } // match: (CMPBconst (ANDLconst _ [m]) [n]) - // cond: 0 <= m && int8(m) < n + // cond: 0 <= int8(m) && int8(m) < n // result: (FlagLT_ULT) for { n := auxIntToInt8(v.AuxInt) @@ -6894,7 +6894,7 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value) bool { break } m := auxIntToInt32(v_0.AuxInt) - if !(0 <= m && int8(m) < n) { + if !(0 <= int8(m) && int8(m) < n) { break } v.reset(OpAMD64FlagLT_ULT) @@ -8243,7 +8243,7 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value) bool { return true } // match: (CMPWconst (ANDLconst _ [m]) [n]) - // cond: 0 <= m && int16(m) < n + // cond: 0 <= int16(m) && int16(m) < n // result: (FlagLT_ULT) for { n := auxIntToInt16(v.AuxInt) @@ -8251,7 +8251,7 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value) bool { break } m := auxIntToInt32(v_0.AuxInt) - if !(0 <= m && int16(m) < n) { + if !(0 <= int16(m) && int16(m) < n) { break } v.reset(OpAMD64FlagLT_ULT) diff --git a/test/fixedbugs/issue41872.go b/test/fixedbugs/issue41872.go new file mode 100644 index 0000000000..837d61ae0a --- /dev/null +++ b/test/fixedbugs/issue41872.go @@ -0,0 +1,26 @@ +// run + +// Copyright 2020 The Go Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in +// the LICENSE file. + +package main + +//go:noinline +func f8(x int32) bool { + return byte(x&0xc0) == 64 +} + +//go:noinline +func f16(x int32) bool { + return uint16(x&0x8040) == 64 +} + +func main() { + if !f8(64) { + panic("wanted true, got false") + } + if !f16(64) { + panic("wanted true, got false") + } +} -- cgit v1.3 From e43ef8dda2d2baeca7f42a50cc92f527e6826b9f Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 12 Oct 2020 17:19:49 -0700 Subject: test: add test that fails with gofrontend The gofrontend code doesn't correctly handle inlining a function that refers to a constant with methods. For #35739 Change-Id: I6bd0b5cd4272dbe9969634b4821e668acacfdcf9 Reviewed-on: https://go-review.googlesource.com/c/go/+/261662 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- test/fixedbugs/issue35739.dir/a.go | 15 +++++++++++++++ test/fixedbugs/issue35739.dir/b.go | 11 +++++++++++ test/fixedbugs/issue35739.go | 9 +++++++++ 3 files changed, 35 insertions(+) create mode 100644 test/fixedbugs/issue35739.dir/a.go create mode 100644 test/fixedbugs/issue35739.dir/b.go create mode 100644 test/fixedbugs/issue35739.go (limited to 'test/fixedbugs') diff --git a/test/fixedbugs/issue35739.dir/a.go b/test/fixedbugs/issue35739.dir/a.go new file mode 100644 index 0000000000..b79503e996 --- /dev/null +++ b/test/fixedbugs/issue35739.dir/a.go @@ -0,0 +1,15 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type myError string + +func (e myError) Error() string { return string(e) } + +const myErrorVal myError = "error" + +func IsMyError(err error) bool { + return err == error(myErrorVal) +} diff --git a/test/fixedbugs/issue35739.dir/b.go b/test/fixedbugs/issue35739.dir/b.go new file mode 100644 index 0000000000..8d22aac8d6 --- /dev/null +++ b/test/fixedbugs/issue35739.dir/b.go @@ -0,0 +1,11 @@ +// Copyright 2020 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 b + +import "./a" + +func F(err error) bool { + return a.IsMyError(err) +} diff --git a/test/fixedbugs/issue35739.go b/test/fixedbugs/issue35739.go new file mode 100644 index 0000000000..26f09d8c1b --- /dev/null +++ b/test/fixedbugs/issue35739.go @@ -0,0 +1,9 @@ +// compiledir + +// Copyright 2020 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. + +// Issue 35739: gccgo inlining error with constant with method. + +package ignored -- cgit v1.3 From 76a615b20a943b7255ac1cb3944df62a1dbc882c Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Sat, 17 Oct 2020 01:10:06 -0700 Subject: cmd/compile: fix defer/go calls to variadic unsafe-uintptr functions Before generating wrapper function, turn any f(a, b, []T{c, d, e}...) calls back into f(a, b, c, d, e). This allows the existing code for recognizing and specially handling unsafe.Pointer->uintptr conversions to correctly handle variadic arguments too. Fixes #41460. Change-Id: I0a1255abdd1bd5dafd3e89547aedd4aec878394c Reviewed-on: https://go-review.googlesource.com/c/go/+/263297 Trust: Matthew Dempsky Trust: Cuong Manh Le Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/gc/walk.go | 10 ++++++++++ test/fixedbugs/issue24491a.go | 3 --- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 05a049b3cc..9df288ea65 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -3881,6 +3881,16 @@ func wrapCall(n *Node, init *Nodes) *Node { } isBuiltinCall := n.Op != OCALLFUNC && n.Op != OCALLMETH && n.Op != OCALLINTER + + // Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e). + if !isBuiltinCall && n.IsDDD() { + last := n.List.Len() - 1 + if va := n.List.Index(last); va.Op == OSLICELIT { + n.List.Set(append(n.List.Slice()[:last], va.List.Slice()...)) + n.SetIsDDD(false) + } + } + // origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion. origArgs := make([]*Node, n.List.Len()) t := nod(OTFUNC, nil, nil) diff --git a/test/fixedbugs/issue24491a.go b/test/fixedbugs/issue24491a.go index 3c595798b5..8accf8c0a3 100644 --- a/test/fixedbugs/issue24491a.go +++ b/test/fixedbugs/issue24491a.go @@ -34,9 +34,6 @@ func test(s string, p, q uintptr, rest ...uintptr) int { panic(s + ": q failed") } for _, r := range rest { - // TODO(mdempsky): Remove. - break - if *(*string)(unsafe.Pointer(r)) != "ok" { panic(s + ": r[i] failed") } -- cgit v1.3 From c216ae80c965acb9641d94d5f58c206bd0cf7d66 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 19 Oct 2020 14:14:40 -0700 Subject: cmd/compile: fix ICE in reporting of invalid recursive types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit asNode(t.Nod).Name.Param will be nil for builtin types (i.e., the universal predeclared types and unsafe.Pointer). These types can't be part of a cycle anyway, so we can just skip them. Fixes #42075. Change-Id: Ic7a44de65c6bfd16936545dee25e36de8850acf3 Reviewed-on: https://go-review.googlesource.com/c/go/+/263717 Trust: Matthew Dempsky Trust: Daniel Martí Reviewed-by: Daniel Martí --- src/cmd/compile/internal/gc/align.go | 2 +- test/fixedbugs/issue42075.go | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue42075.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go index 5af403afa3..4bc454df22 100644 --- a/src/cmd/compile/internal/gc/align.go +++ b/src/cmd/compile/internal/gc/align.go @@ -199,7 +199,7 @@ func findTypeLoop(t *types.Type, path *[]*types.Type) bool { } *path = append(*path, t) - if findTypeLoop(asNode(t.Nod).Name.Param.Ntype.Type, path) { + if p := asNode(t.Nod).Name.Param; p != nil && findTypeLoop(p.Ntype.Type, path) { return true } *path = (*path)[:len(*path)-1] diff --git a/test/fixedbugs/issue42075.go b/test/fixedbugs/issue42075.go new file mode 100644 index 0000000000..af85fb281d --- /dev/null +++ b/test/fixedbugs/issue42075.go @@ -0,0 +1,16 @@ +// errorcheck + +// Copyright 2020 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 p + +import "unsafe" + +type T struct { // ERROR "recursive type" + x int + p unsafe.Pointer + + f T +} -- cgit v1.3 From bccdd31252c9771ef2e8dae0402251163a081b56 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Mon, 19 Oct 2020 18:32:15 +0700 Subject: cmd/compile: use type position for error message in align.go This helps the compiler reports the right place where the type declared, instead of relying on global lineno, which maybe set to wrong value at the time the error is reported. Fixes #42058 Change-Id: I06d34aa9b0236d122f4a0d72e66675ded022baac Reviewed-on: https://go-review.googlesource.com/c/go/+/263597 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le Reviewed-by: Matthew Dempsky TryBot-Result: Go Bot --- src/cmd/compile/internal/gc/align.go | 10 +++++----- src/go/types/stdlib_test.go | 2 ++ test/fixedbugs/issue42058a.go | 13 +++++++++++++ test/fixedbugs/issue42058b.go | 13 +++++++++++++ 4 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 test/fixedbugs/issue42058a.go create mode 100644 test/fixedbugs/issue42058b.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go index 4bc454df22..a3a0c8fce8 100644 --- a/src/cmd/compile/internal/gc/align.go +++ b/src/cmd/compile/internal/gc/align.go @@ -86,7 +86,7 @@ func expandiface(t *types.Type) { sort.Sort(methcmp(methods)) if int64(len(methods)) >= thearch.MAXWIDTH/int64(Widthptr) { - yyerror("interface too large") + yyerrorl(typePos(t), "interface too large") } for i, m := range methods { m.Offset = int64(i) * int64(Widthptr) @@ -150,7 +150,7 @@ func widstruct(errtype *types.Type, t *types.Type, o int64, flag int) int64 { maxwidth = 1<<31 - 1 } if o >= maxwidth { - yyerror("type %L too large", errtype) + yyerrorl(typePos(errtype), "type %L too large", errtype) o = 8 // small but nonzero } } @@ -381,7 +381,7 @@ func dowidth(t *types.Type) { t1 := t.ChanArgs() dowidth(t1) // just in case if t1.Elem().Width >= 1<<16 { - yyerror("channel element type too large (>64kB)") + yyerrorl(typePos(t1), "channel element type too large (>64kB)") } w = 1 // anything will do @@ -414,7 +414,7 @@ func dowidth(t *types.Type) { if t.Elem().Width != 0 { cap := (uint64(thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width) if uint64(t.NumElem()) > cap { - yyerror("type %L larger than address space", t) + yyerrorl(typePos(t), "type %L larger than address space", t) } } w = t.NumElem() * t.Elem().Width @@ -456,7 +456,7 @@ func dowidth(t *types.Type) { } if Widthptr == 4 && w != int64(int32(w)) { - yyerror("type %v too large", t) + yyerrorl(typePos(t), "type %v too large", t) } t.Width = w diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go index f5a3273fa1..669e7bec20 100644 --- a/src/go/types/stdlib_test.go +++ b/src/go/types/stdlib_test.go @@ -183,6 +183,8 @@ func TestStdFixed(t *testing.T) { "issue31747.go", // go/types does not have constraints on language level (-lang=go1.12) (see #31793) "issue34329.go", // go/types does not have constraints on language level (-lang=go1.13) (see #31793) "bug251.go", // issue #34333 which was exposed with fix for #34151 + "issue42058a.go", // go/types does not have constraints on channel element size + "issue42058b.go", // go/types does not have constraints on channel element size ) } diff --git a/test/fixedbugs/issue42058a.go b/test/fixedbugs/issue42058a.go new file mode 100644 index 0000000000..67751a1b0c --- /dev/null +++ b/test/fixedbugs/issue42058a.go @@ -0,0 +1,13 @@ +// errorcheck + +// Copyright 2020 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 p + +var c chan [2 << 16]byte // ERROR "channel element type too large" + +type T [1 << 17]byte + +var x chan T // ERROR "channel element type too large" diff --git a/test/fixedbugs/issue42058b.go b/test/fixedbugs/issue42058b.go new file mode 100644 index 0000000000..03f86ee1b1 --- /dev/null +++ b/test/fixedbugs/issue42058b.go @@ -0,0 +1,13 @@ +// errorcheck + +// Copyright 2020 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 p + +var c chan [2 << 16]byte // ERROR "channel element type too large" + +func f() { + _ = 42 +} -- cgit v1.3 From c9c64886ef041b096d7f93c4e7d2ef5faf87ad43 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 19 Oct 2020 10:40:24 -0400 Subject: cmd/internal/obj: reject too large symbols We never supported symbol larger than 2GB (issue #9862), so the object file uses 32-bit for symbol sizes. Check and reject too large symbol before truncating its size. Fixes #42054. Change-Id: I0d1d585ebdba9556f2fd3a97043bd4296d5cc9e4 Reviewed-on: https://go-review.googlesource.com/c/go/+/263641 Trust: Cherry Zhang Trust: Cuong Manh Le Run-TryBot: Cherry Zhang Reviewed-by: Cuong Manh Le TryBot-Result: Go Bot --- src/cmd/internal/obj/objfile.go | 7 +++++++ src/cmd/internal/obj/objfile_test.go | 36 ++++++++++++++++++++++++++++++++++++ test/fixedbugs/issue4348.go | 4 +++- 3 files changed, 46 insertions(+), 1 deletion(-) (limited to 'test/fixedbugs') diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index a08de891d3..a24a7b878f 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -261,6 +261,10 @@ func (w *writer) StringTable() { } } +// cutoff is the maximum data section size permitted by the linker +// (see issue #9862). +const cutoff = int64(2e9) // 2 GB (or so; looks better in errors than 2^31) + func (w *writer) Sym(s *LSym) { abi := uint16(s.ABI()) if s.Static() { @@ -325,6 +329,9 @@ func (w *writer) Sym(s *LSym) { // don't bother setting align to 1. } } + if s.Size > cutoff { + w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff) + } var o goobj.Sym o.SetName(name, w.Writer) o.SetABI(abi) diff --git a/src/cmd/internal/obj/objfile_test.go b/src/cmd/internal/obj/objfile_test.go index 155701fa4e..146627b62b 100644 --- a/src/cmd/internal/obj/objfile_test.go +++ b/src/cmd/internal/obj/objfile_test.go @@ -5,9 +5,16 @@ package obj import ( + "bytes" "cmd/internal/goobj" "cmd/internal/sys" + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "path/filepath" "testing" + "unsafe" ) var dummyArch = LinkArch{Arch: sys.ArchAMD64} @@ -85,3 +92,32 @@ func TestContentHash(t *testing.T) { } } } + +func TestSymbolTooLarge(t *testing.T) { // Issue 42054 + testenv.MustHaveGoBuild(t) + if unsafe.Sizeof(uintptr(0)) < 8 { + t.Skip("skip on 32-bit architectures") + } + + tmpdir, err := ioutil.TempDir("", "TestSymbolTooLarge") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + + src := filepath.Join(tmpdir, "p.go") + err = ioutil.WriteFile(src, []byte("package p; var x [1<<32]byte"), 0666) + if err != nil { + t.Fatalf("failed to write source file: %v\n", err) + } + obj := filepath.Join(tmpdir, "p.o") + cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", obj, src) + out, err := cmd.CombinedOutput() + if err == nil { + t.Fatalf("did not fail\noutput: %s", out) + } + const want = "symbol too large" + if !bytes.Contains(out, []byte(want)) { + t.Errorf("unexpected error message: want: %q, got: %s", want, out) + } +} diff --git a/test/fixedbugs/issue4348.go b/test/fixedbugs/issue4348.go index c59b6b8caa..8b1a56c1d5 100644 --- a/test/fixedbugs/issue4348.go +++ b/test/fixedbugs/issue4348.go @@ -1,4 +1,4 @@ -// compile +// skip // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -7,6 +7,8 @@ // Issue 4348. After switch to 64-bit ints the compiler generates // illegal instructions when using large array bounds or indexes. +// Skip. We reject symbols larger that 2GB (Issue #9862). + package main // 1<<32 on a 64-bit machine, 1 otherwise. -- cgit v1.3 From 933721b8c7f981229974e2603850c2e9a7ffc5a1 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 22 Oct 2020 13:11:16 -0700 Subject: cmd/compile: fix storeType to handle pointers to go:notinheap types storeType splits compound stores up into a scalar parts and a pointer parts. The scalar part happens unconditionally, and the pointer part happens under the guard of a write barrier check. Types which are declared as pointers, but are represented as scalars because they might have "bad" values, were not handled correctly here. They ended up not getting stored in either set. Fixes #42032 Change-Id: I46f6600075c0c370e640b807066247237f93c7ac Reviewed-on: https://go-review.googlesource.com/c/go/+/264300 Trust: Keith Randall Reviewed-by: Ian Lance Taylor --- src/cmd/compile/internal/gc/ssa.go | 8 +++++++- test/fixedbugs/issue42032.go | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue42032.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 4769c2c7d9..4488337924 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -5222,7 +5222,10 @@ func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip ski case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex(): s.store(t, left, right) case t.IsPtrShaped(): - // no scalar fields. + if t.IsPtr() && t.Elem().NotInHeap() { + s.store(t, left, right) // see issue 42032 + } + // otherwise, no scalar fields. case t.IsString(): if skip&skipLen != 0 { return @@ -5266,6 +5269,9 @@ func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip ski func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) { switch { case t.IsPtrShaped(): + if t.IsPtr() && t.Elem().NotInHeap() { + break // see issue 42032 + } s.store(t, left, right) case t.IsString(): ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right) diff --git a/test/fixedbugs/issue42032.go b/test/fixedbugs/issue42032.go new file mode 100644 index 0000000000..c456b1db02 --- /dev/null +++ b/test/fixedbugs/issue42032.go @@ -0,0 +1,27 @@ +// run + +// Copyright 2020 The Go Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in +// the LICENSE file. + +package main + +//go:notinheap +type NIH struct { +} + +type T struct { + x *NIH + p *int +} + +var y NIH +var z int + +func main() { + a := []T{{&y, &z}} + a = append(a, T{&y, &z}) + if a[1].x == nil { + panic("pointer not written") + } +} -- cgit v1.3 From 009d71409821a6ac4f1b32aaae2c856c20a29f92 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 22 Oct 2020 16:37:19 -0700 Subject: cmd/compile, runtime: store pointers to go:notinheap types indirectly pointers to go:notinheap types should be treated as scalars. That means they shouldn't be stored directly in interfaces, or directly in reflect.Value.ptr. Also be sure to use uintpr to compare such pointers in reflect.DeepEqual. Fixes #42076 Change-Id: I53735f6d434e9c3108d4940bd1bae14c61ef2a74 Reviewed-on: https://go-review.googlesource.com/c/go/+/264480 Trust: Keith Randall Reviewed-by: Ian Lance Taylor --- src/cmd/compile/internal/gc/subr.go | 6 ++-- src/cmd/compile/internal/gc/typecheck.go | 2 +- src/reflect/deepequal.go | 12 +++++++- src/reflect/value.go | 12 +++++++- src/runtime/netpoll.go | 47 ++++++++++++++++++++++---------- test/fixedbugs/issue42076.go | 21 ++++++++++++++ 6 files changed, 81 insertions(+), 19 deletions(-) create mode 100644 test/fixedbugs/issue42076.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index eccd6f8a74..defefd76b3 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -1854,8 +1854,10 @@ func isdirectiface(t *types.Type) bool { } switch t.Etype { - case TPTR, - TCHAN, + case TPTR: + // Pointers to notinheap types must be stored indirectly. See issue 42076. + return !t.Elem().NotInHeap() + case TCHAN, TMAP, TFUNC, TUNSAFEPTR: diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index ce817db446..8ebeaf1330 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -2516,7 +2516,7 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { n.Left = nod(OADDR, n.Left, nil) n.Left.SetImplicit(true) n.Left = typecheck(n.Left, ctxType|ctxExpr) - } else if tt.IsPtr() && !rcvr.IsPtr() && types.Identical(tt.Elem(), rcvr) { + } else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) { n.Left = nod(ODEREF, n.Left, nil) n.Left.SetImplicit(true) n.Left = typecheck(n.Left, ctxType|ctxExpr) diff --git a/src/reflect/deepequal.go b/src/reflect/deepequal.go index be66464129..d951d8d999 100644 --- a/src/reflect/deepequal.go +++ b/src/reflect/deepequal.go @@ -35,7 +35,17 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool { // and it's safe and valid to get Value's internal pointer. hard := func(v1, v2 Value) bool { switch v1.Kind() { - case Map, Slice, Ptr, Interface: + case Ptr: + if v1.typ.ptrdata == 0 { + // go:notinheap pointers can't be cyclic. + // At least, all of our current uses of go:notinheap have + // that property. The runtime ones aren't cyclic (and we don't use + // DeepEqual on them anyway), and the cgo-generated ones are + // all empty structs. + return false + } + fallthrough + case Map, Slice, Interface: // Nil pointers cannot be cyclic. Avoid putting them in the visited map. return !v1.IsNil() && !v2.IsNil() } diff --git a/src/reflect/value.go b/src/reflect/value.go index bb6371b867..24eab6a2c6 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -90,6 +90,7 @@ func (f flag) ro() flag { // pointer returns the underlying pointer represented by v. // v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer +// if v.Kind() == Ptr, the base type must not be go:notinheap. func (v Value) pointer() unsafe.Pointer { if v.typ.size != ptrSize || !v.typ.pointers() { panic("can't call pointer on a non-pointer Value") @@ -1453,7 +1454,16 @@ func (v Value) Pointer() uintptr { // TODO: deprecate k := v.kind() switch k { - case Chan, Map, Ptr, UnsafePointer: + case Ptr: + if v.typ.ptrdata == 0 { + // Handle pointers to go:notinheap types directly, + // so we never materialize such pointers as an + // unsafe.Pointer. (Such pointers are always indirect.) + // See issue 42076. + return *(*uintptr)(v.ptr) + } + fallthrough + case Chan, Map, UnsafePointer: return uintptr(v.pointer()) case Func: if v.flag&flagMethod != 0 { diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go index 34ea82a7fa..77eb3aa4c6 100644 --- a/src/runtime/netpoll.go +++ b/src/runtime/netpoll.go @@ -79,16 +79,17 @@ type pollDesc struct { lock mutex // protects the following fields fd uintptr closing bool - everr bool // marks event scanning error happened - user uint32 // user settable cookie - rseq uintptr // protects from stale read timers - rg uintptr // pdReady, pdWait, G waiting for read or nil - rt timer // read deadline timer (set if rt.f != nil) - rd int64 // read deadline - wseq uintptr // protects from stale write timers - wg uintptr // pdReady, pdWait, G waiting for write or nil - wt timer // write deadline timer - wd int64 // write deadline + everr bool // marks event scanning error happened + user uint32 // user settable cookie + rseq uintptr // protects from stale read timers + rg uintptr // pdReady, pdWait, G waiting for read or nil + rt timer // read deadline timer (set if rt.f != nil) + rd int64 // read deadline + wseq uintptr // protects from stale write timers + wg uintptr // pdReady, pdWait, G waiting for write or nil + wt timer // write deadline timer + wd int64 // write deadline + self *pollDesc // storage for indirect interface. See (*pollDesc).makeArg. } type pollCache struct { @@ -157,6 +158,7 @@ func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) { pd.wseq++ pd.wg = 0 pd.wd = 0 + pd.self = pd unlock(&pd.lock) var errno int32 @@ -271,14 +273,14 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) { // Copy current seq into the timer arg. // Timer func will check the seq against current descriptor seq, // if they differ the descriptor was reused or timers were reset. - pd.rt.arg = pd + pd.rt.arg = pd.makeArg() pd.rt.seq = pd.rseq resettimer(&pd.rt, pd.rd) } } else if pd.rd != rd0 || combo != combo0 { pd.rseq++ // invalidate current timers if pd.rd > 0 { - modtimer(&pd.rt, pd.rd, 0, rtf, pd, pd.rseq) + modtimer(&pd.rt, pd.rd, 0, rtf, pd.makeArg(), pd.rseq) } else { deltimer(&pd.rt) pd.rt.f = nil @@ -287,14 +289,14 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) { if pd.wt.f == nil { if pd.wd > 0 && !combo { pd.wt.f = netpollWriteDeadline - pd.wt.arg = pd + pd.wt.arg = pd.makeArg() pd.wt.seq = pd.wseq resettimer(&pd.wt, pd.wd) } } else if pd.wd != wd0 || combo != combo0 { pd.wseq++ // invalidate current timers if pd.wd > 0 && !combo { - modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd, pd.wseq) + modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd.makeArg(), pd.wseq) } else { deltimer(&pd.wt) pd.wt.f = nil @@ -547,3 +549,20 @@ func (c *pollCache) alloc() *pollDesc { unlock(&c.lock) return pd } + +// makeArg converts pd to an interface{}. +// makeArg does not do any allocation. Normally, such +// a conversion requires an allocation because pointers to +// go:notinheap types (which pollDesc is) must be stored +// in interfaces indirectly. See issue 42076. +func (pd *pollDesc) makeArg() (i interface{}) { + x := (*eface)(unsafe.Pointer(&i)) + x._type = pdType + x.data = unsafe.Pointer(&pd.self) + return +} + +var ( + pdEface interface{} = (*pollDesc)(nil) + pdType *_type = efaceOf(&pdEface)._type +) diff --git a/test/fixedbugs/issue42076.go b/test/fixedbugs/issue42076.go new file mode 100644 index 0000000000..3e954813c9 --- /dev/null +++ b/test/fixedbugs/issue42076.go @@ -0,0 +1,21 @@ +// run + +// Copyright 2020 The Go Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in +// the LICENSE file. + +package main + +import "reflect" + +//go:notinheap +type NIH struct { +} + +var x, y NIH + +func main() { + if reflect.DeepEqual(&x, &y) != true { + panic("should report true") + } +} -- cgit v1.3 From b85c2dd56c4ecc7bf445bd1615467ecd38598eee Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sat, 24 Oct 2020 20:58:38 -0400 Subject: cmd/link: enable internal linking by default on darwin/arm64 With previous CLs, internal linking without cgo should work well. Enable it by default. And stop always requiring cgo. Enable tests that were previously disabled due to the lack of internal linking. Updates #38485. Change-Id: I45125b9c263fd21d6847aa6b14ecaea3a2989b29 Reviewed-on: https://go-review.googlesource.com/c/go/+/265121 Trust: Cherry Zhang Reviewed-by: Austin Clements Reviewed-by: Than McIntosh --- src/cmd/go/internal/load/pkg.go | 4 ---- src/cmd/internal/sys/supported.go | 2 +- src/cmd/link/internal/ld/config.go | 4 +--- src/cmd/nm/nm_cgo_test.go | 5 ----- src/internal/testenv/testenv.go | 2 +- test/fixedbugs/bug429_run.go | 4 ---- test/fixedbugs/issue21576.go | 4 ---- 7 files changed, 3 insertions(+), 22 deletions(-) (limited to 'test/fixedbugs') diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 4c541b9017..ff744ee9fa 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -1964,10 +1964,6 @@ func externalLinkingForced(p *Package) bool { } case "ios": return true - case "darwin": - if cfg.BuildContext.GOARCH == "arm64" { - return true - } } // Currently build modes c-shared, pie (on systems that do not diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go index 1d813bbb47..afc81381fd 100644 --- a/src/cmd/internal/sys/supported.go +++ b/src/cmd/internal/sys/supported.go @@ -39,7 +39,7 @@ func MustLinkExternal(goos, goarch string) bool { if goarch != "arm64" { return true } - case "darwin", "ios": + case "ios": if goarch == "arm64" { return true } diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index 54a94cebba..0cb3cc25c0 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -185,7 +185,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { }() } - if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) && !(objabi.GOOS == "darwin" && objabi.GOARCH == "arm64") { // XXX allow internal linking for darwin/arm64 but not change the default + if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) { return true, fmt.Sprintf("%s/%s requires external linking", objabi.GOOS, objabi.GOARCH) } @@ -261,8 +261,6 @@ func determineLinkMode(ctxt *Link) { default: if extNeeded || (iscgo && externalobj) { ctxt.LinkMode = LinkExternal - } else if ctxt.IsDarwin() && ctxt.IsARM64() { - ctxt.LinkMode = LinkExternal // default to external linking for now } else { ctxt.LinkMode = LinkInternal } diff --git a/src/cmd/nm/nm_cgo_test.go b/src/cmd/nm/nm_cgo_test.go index 58f2c24908..9a257e0ed2 100644 --- a/src/cmd/nm/nm_cgo_test.go +++ b/src/cmd/nm/nm_cgo_test.go @@ -15,11 +15,6 @@ func canInternalLink() bool { switch runtime.GOOS { case "aix": return false - case "darwin": - switch runtime.GOARCH { - case "arm64": - return false - } case "dragonfly": return false case "freebsd": diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go index 0ee6355ee3..dff68869bd 100644 --- a/src/internal/testenv/testenv.go +++ b/src/internal/testenv/testenv.go @@ -201,7 +201,7 @@ func CanInternalLink() bool { if runtime.GOARCH != "arm64" { return false } - case "darwin", "ios": + case "ios": if runtime.GOARCH == "arm64" { return false } diff --git a/test/fixedbugs/bug429_run.go b/test/fixedbugs/bug429_run.go index 60cc5b62de..c2bb1b85cb 100644 --- a/test/fixedbugs/bug429_run.go +++ b/test/fixedbugs/bug429_run.go @@ -1,10 +1,6 @@ // run // +build !nacl,!js -// +build !darwin !arm64 - -// Skip on darwin/arm64 as it requires external linking, which brings in -// cgo, causing deadlock detection not working. // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/fixedbugs/issue21576.go b/test/fixedbugs/issue21576.go index 3797a8c9ba..ae6161ccf5 100644 --- a/test/fixedbugs/issue21576.go +++ b/test/fixedbugs/issue21576.go @@ -1,10 +1,6 @@ // run // +build !nacl,!js -// +build !darwin !arm64 - -// Skip on darwin/arm64 as it requires external linking, which brings in -// cgo, causing deadlock detection not working. // Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style -- cgit v1.3 From 7191f1136b1526703c5af7fc04ff948e3a6c26b9 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 30 Oct 2020 10:36:31 -0700 Subject: cmd/compile: fix reassignVisitor reassignVisitor was short-circuiting on assignment statements after checking the LHS, but there might be further assignment statements nested within the RHS expressions. Fixes #42284. Change-Id: I175eef87513b973ed5ebe6a6527adb9766dde6cf Reviewed-on: https://go-review.googlesource.com/c/go/+/266618 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky Reviewed-by: Cuong Manh Le Reviewed-by: David Chase TryBot-Result: Go Bot --- src/cmd/compile/internal/gc/inl.go | 2 -- test/fixedbugs/issue42284.dir/a.go | 23 +++++++++++++++++++++++ test/fixedbugs/issue42284.dir/b.go | 15 +++++++++++++++ test/fixedbugs/issue42284.go | 7 +++++++ 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 test/fixedbugs/issue42284.dir/a.go create mode 100644 test/fixedbugs/issue42284.dir/b.go create mode 100644 test/fixedbugs/issue42284.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 5b58908299..8a5c6d8666 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -839,14 +839,12 @@ func (v *reassignVisitor) visit(n *Node) *Node { if n.Left == v.name && n != v.name.Name.Defn { return n } - return nil case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE: for _, p := range n.List.Slice() { if p == v.name && n != v.name.Name.Defn { return n } } - return nil } if a := v.visit(n.Left); a != nil { return a diff --git a/test/fixedbugs/issue42284.dir/a.go b/test/fixedbugs/issue42284.dir/a.go new file mode 100644 index 0000000000..e1271af32d --- /dev/null +++ b/test/fixedbugs/issue42284.dir/a.go @@ -0,0 +1,23 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +type I interface{ M() } +type T int + +func (T) M() {} // ERROR "can inline T.M" + +func F(i I) I { // ERROR "can inline F" "leaking param: i to result ~r1 level=0" + i = nil + return i +} + +func g() { // ERROR "can inline g" + // BAD: T(0) could be stack allocated. + i := F(T(0)) // ERROR "inlining call to F" "T\(0\) escapes to heap" + + // Testing that we do NOT devirtualize here: + i.M() +} diff --git a/test/fixedbugs/issue42284.dir/b.go b/test/fixedbugs/issue42284.dir/b.go new file mode 100644 index 0000000000..3305166db0 --- /dev/null +++ b/test/fixedbugs/issue42284.dir/b.go @@ -0,0 +1,15 @@ +// Copyright 2020 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 b + +import "./a" + +func g() { // ERROR "can inline g" + // BAD: T(0) could be stack allocated. + i := a.F(a.T(0)) // ERROR "inlining call to a.F" "a.T\(0\) escapes to heap" + + // Testing that we do NOT devirtualize here: + i.M() +} diff --git a/test/fixedbugs/issue42284.go b/test/fixedbugs/issue42284.go new file mode 100644 index 0000000000..e5d6173f5c --- /dev/null +++ b/test/fixedbugs/issue42284.go @@ -0,0 +1,7 @@ +// errorcheckdir -0 -m + +// Copyright 2020 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 ignored -- cgit v1.3 From 063a91c0abef445154df1ba34ffb500eeccfe8bc Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 30 Oct 2020 12:58:28 -0700 Subject: cmd/compile: fix recognition of unnamed return variables In golang.org/cl/266199, I reused the existing code in inlining that recognizes anonymous variables. However, it turns out that code mistakenly recognizes anonymous return parameters as named when inlining a function from the same package. The issue is funcargs (which is only used for functions parsed from source) synthesizes ~r names for anonymous return parameters, but funcargs2 (which is only used for functions imported from export data) does not. This CL fixes the behavior so that anonymous return parameters are handled identically whether a function is inlined within the same package or across packages. It also adds a proper cross-package test case demonstrating #33160 is fixed in both cases. Change-Id: Iaa39a23f5666979a1f5ca6d09fc8c398e55b784c Reviewed-on: https://go-review.googlesource.com/c/go/+/266719 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le Reviewed-by: David Chase Trust: Matthew Dempsky --- src/cmd/compile/internal/gc/inl.go | 2 +- src/cmd/compile/internal/logopt/logopt_test.go | 8 ++++---- test/fixedbugs/issue42284.dir/a.go | 9 ++++++++- test/fixedbugs/issue42284.dir/b.go | 5 ++++- 4 files changed, 17 insertions(+), 7 deletions(-) (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 8a5c6d8666..253036fea6 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -1054,7 +1054,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node { var retvars []*Node for i, t := range fn.Type.Results().Fields().Slice() { var m *Node - if n := asNode(t.Nname); n != nil && !n.isBlank() { + if n := asNode(t.Nname); n != nil && !n.isBlank() && !strings.HasPrefix(n.Sym.Name, "~r") { m = inlvar(n) m = typecheck(m, ctxExpr) inlvars[n] = m diff --git a/src/cmd/compile/internal/logopt/logopt_test.go b/src/cmd/compile/internal/logopt/logopt_test.go index fca85c10fb..51bab49518 100644 --- a/src/cmd/compile/internal/logopt/logopt_test.go +++ b/src/cmd/compile/internal/logopt/logopt_test.go @@ -213,15 +213,15 @@ func s15a8(x *[15]int64) [15]int64 { `"relatedInformation":[`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y := z (assign-pair)"},`+ - `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~r1 = y:"},`+ + `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~R0 = y:"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from \u0026y.b (address-of)"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+ - `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~r1 = \u003cN\u003e (assign-pair)"},`+ - `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r2 = ~r1:"},`+ - `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return (*int)(~r1) (return)"}]}`) + `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~R0 = \u003cN\u003e (assign-pair)"},`+ + `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r2 = ~R0:"},`+ + `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return (*int)(~R0) (return)"}]}`) }) } diff --git a/test/fixedbugs/issue42284.dir/a.go b/test/fixedbugs/issue42284.dir/a.go index e1271af32d..ffe9310be3 100644 --- a/test/fixedbugs/issue42284.dir/a.go +++ b/test/fixedbugs/issue42284.dir/a.go @@ -9,12 +9,19 @@ type T int func (T) M() {} // ERROR "can inline T.M" +func E() I { // ERROR "can inline E" + return T(0) // ERROR "T\(0\) escapes to heap" +} + func F(i I) I { // ERROR "can inline F" "leaking param: i to result ~r1 level=0" i = nil return i } -func g() { // ERROR "can inline g" +func g() { + h := E() // ERROR "inlining call to E" "T\(0\) does not escape" + h.M() // ERROR "devirtualizing h.M to T" + // BAD: T(0) could be stack allocated. i := F(T(0)) // ERROR "inlining call to F" "T\(0\) escapes to heap" diff --git a/test/fixedbugs/issue42284.dir/b.go b/test/fixedbugs/issue42284.dir/b.go index 3305166db0..652aa32122 100644 --- a/test/fixedbugs/issue42284.dir/b.go +++ b/test/fixedbugs/issue42284.dir/b.go @@ -6,7 +6,10 @@ package b import "./a" -func g() { // ERROR "can inline g" +func g() { + h := a.E() // ERROR "inlining call to a.E" "a.I\(a.T\(0\)\) does not escape" + h.M() // ERROR "devirtualizing h.M to a.T" + // BAD: T(0) could be stack allocated. i := a.F(a.T(0)) // ERROR "inlining call to a.F" "a.T\(0\) escapes to heap" -- cgit v1.3 From 5736eb0013cb8c9b67432c98b08f68e9f370810c Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 29 Oct 2020 01:13:16 -0700 Subject: cmd/compile: support inlining of type switches This CL adds support for inlining type switches, including exporting and importing them. Type switches are represented mostly the same as expression switches. However, if the type switch guard includes a short variable declaration, then there are two differences: (1) there's an ONONAME (in the OTYPESW's Left) to represent the overall pseudo declaration; and (2) there's an ONAME (in each OCASE's Rlist) to represent the per-case variables. For simplicity, this CL simply writes out each variable separately using iimport/iiexport's normal Vargen mechanism for disambiguating identically named variables within a function. This could be improved somewhat, but inlinable type switches are probably too uncommon to merit the complexity. While here, remove "case OCASE" from typecheck1. We only type check "case" clauses as part of a "select" or "switch" statement, never as standalone statements. Fixes #37837 Change-Id: I8f42f6c9afdd821d6202af4a6bf1dbcbba0ef424 Reviewed-on: https://go-review.googlesource.com/c/go/+/266203 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Keith Randall Trust: Matthew Dempsky --- src/cmd/compile/internal/gc/iexport.go | 40 ++++++++++++++++++++++++++----- src/cmd/compile/internal/gc/iimport.go | 41 +++++++++++++++++++++++++------- src/cmd/compile/internal/gc/inl.go | 4 ---- src/cmd/compile/internal/gc/typecheck.go | 5 ---- test/fixedbugs/issue37837.dir/a.go | 33 +++++++++++++++++++++++++ test/fixedbugs/issue37837.dir/b.go | 32 +++++++++++++++++++++++++ test/fixedbugs/issue37837.go | 7 ++++++ test/inline.go | 3 +-- 8 files changed, 140 insertions(+), 25 deletions(-) create mode 100644 test/fixedbugs/issue37837.dir/a.go create mode 100644 test/fixedbugs/issue37837.dir/b.go create mode 100644 test/fixedbugs/issue37837.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go index 9bc1f64600..1f53d8ca7d 100644 --- a/src/cmd/compile/internal/gc/iexport.go +++ b/src/cmd/compile/internal/gc/iexport.go @@ -1138,13 +1138,10 @@ func (w *exportWriter) stmt(n *Node) { w.pos(n.Pos) w.stmtList(n.Ninit) w.exprsOrNil(n.Left, nil) - w.stmtList(n.List) + w.caseList(n) - case OCASE: - w.op(OCASE) - w.pos(n.Pos) - w.stmtList(n.List) - w.stmtList(n.Nbody) + // case OCASE: + // handled by caseList case OFALL: w.op(OFALL) @@ -1168,6 +1165,24 @@ func (w *exportWriter) stmt(n *Node) { } } +func (w *exportWriter) caseList(sw *Node) { + namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil + + cases := sw.List.Slice() + w.uint64(uint64(len(cases))) + for _, cas := range cases { + if cas.Op != OCASE { + Fatalf("expected OCASE, got %v", cas) + } + w.pos(cas.Pos) + w.stmtList(cas.List) + if namedTypeSwitch { + w.localName(cas.Rlist.First()) + } + w.stmtList(cas.Nbody) + } +} + func (w *exportWriter) exprList(list Nodes) { for _, n := range list.Slice() { w.expr(n) @@ -1232,6 +1247,19 @@ func (w *exportWriter) expr(n *Node) { w.op(OTYPE) w.typ(n.Type) + case OTYPESW: + w.op(OTYPESW) + w.pos(n.Pos) + var s *types.Sym + if n.Left != nil { + if n.Left.Op != ONONAME { + Fatalf("expected ONONAME, got %v", n.Left) + } + s = n.Left.Sym + } + w.localIdent(s, 0) // declared pseudo-variable, if any + w.exprsOrNil(n.Right, nil) + // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: // should have been resolved by typechecking - handled by default case diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go index 7f2b05f288..c0114d0e53 100644 --- a/src/cmd/compile/internal/gc/iimport.go +++ b/src/cmd/compile/internal/gc/iimport.go @@ -784,6 +784,28 @@ func (r *importReader) stmtList() []*Node { return list } +func (r *importReader) caseList(sw *Node) []*Node { + namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil + + cases := make([]*Node, r.uint64()) + for i := range cases { + cas := nodl(r.pos(), OCASE, nil, nil) + cas.List.Set(r.stmtList()) + if namedTypeSwitch { + // Note: per-case variables will have distinct, dotted + // names after import. That's okay: swt.go only needs + // Sym for diagnostics anyway. + caseVar := newnamel(cas.Pos, r.ident()) + declare(caseVar, dclcontext) + cas.Rlist.Set1(caseVar) + caseVar.Name.Defn = sw.Left + } + cas.Nbody.Set(r.stmtList()) + cases[i] = cas + } + return cases +} + func (r *importReader) exprList() []*Node { var list []*Node for { @@ -831,6 +853,14 @@ func (r *importReader) node() *Node { case OTYPE: return typenod(r.typ()) + case OTYPESW: + n := nodl(r.pos(), OTYPESW, nil, nil) + if s := r.ident(); s != nil { + n.Left = npos(n.Pos, newnoname(s)) + } + n.Right, _ = r.exprsOrNil() + return n + // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: // unreachable - should have been resolved by typechecking @@ -1025,16 +1055,11 @@ func (r *importReader) node() *Node { n := nodl(r.pos(), op, nil, nil) n.Ninit.Set(r.stmtList()) n.Left, _ = r.exprsOrNil() - n.List.Set(r.stmtList()) + n.List.Set(r.caseList(n)) return n - case OCASE: - n := nodl(r.pos(), OCASE, nil, nil) - n.List.Set(r.exprList()) - // TODO(gri) eventually we must declare variables for type switch - // statements (type switch statements are not yet exported) - n.Nbody.Set(r.stmtList()) - return n + // case OCASE: + // handled by caseList case OFALL: n := nodl(r.pos(), OFALL, nil, nil) diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 253036fea6..139572f652 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -392,13 +392,9 @@ func (v *hairyVisitor) visit(n *Node) bool { v.reason = "call to recover" return true - case OCALLPART: - // OCALLPART is inlineable, but no extra cost to the budget - case OCLOSURE, ORANGE, OSELECT, - OTYPESW, OGO, ODEFER, ODCLTYPE, // can't print yet diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 8ebeaf1330..cbba5ff79c 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -2065,11 +2065,6 @@ func typecheck1(n *Node, top int) (res *Node) { n.Type = nil return n - case OCASE: - ok |= ctxStmt - typecheckslice(n.List.Slice(), ctxExpr) - typecheckslice(n.Nbody.Slice(), ctxStmt) - case ODCLFUNC: ok |= ctxStmt typecheckfunc(n) diff --git a/test/fixedbugs/issue37837.dir/a.go b/test/fixedbugs/issue37837.dir/a.go new file mode 100644 index 0000000000..49d830ffbc --- /dev/null +++ b/test/fixedbugs/issue37837.dir/a.go @@ -0,0 +1,33 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +func F(i interface{}) int { // ERROR "can inline F" "i does not escape" + switch i.(type) { + case nil: + return 0 + case int: + return 1 + case float64: + return 2 + default: + return 3 + } +} + +func G(i interface{}) interface{} { // ERROR "can inline G" "leaking param: i" + switch i := i.(type) { + case nil: // ERROR "moved to heap: i" + return &i + case int: // ERROR "moved to heap: i" + return &i + case float64: // ERROR "moved to heap: i" + return &i + case string, []byte: // ERROR "moved to heap: i" + return &i + default: // ERROR "moved to heap: i" + return &i + } +} diff --git a/test/fixedbugs/issue37837.dir/b.go b/test/fixedbugs/issue37837.dir/b.go new file mode 100644 index 0000000000..461f5c7a55 --- /dev/null +++ b/test/fixedbugs/issue37837.dir/b.go @@ -0,0 +1,32 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +func main() { + // Test that inlined type switches without short variable + // declarations work correctly. + check(0, a.F(nil)) // ERROR "inlining call to a.F" + check(1, a.F(0)) // ERROR "inlining call to a.F" "does not escape" + check(2, a.F(0.0)) // ERROR "inlining call to a.F" "does not escape" + check(3, a.F("")) // ERROR "inlining call to a.F" "does not escape" + + // Test that inlined type switches with short variable + // declarations work correctly. + _ = a.G(nil).(*interface{}) // ERROR "inlining call to a.G" + _ = a.G(1).(*int) // ERROR "inlining call to a.G" "does not escape" + _ = a.G(2.0).(*float64) // ERROR "inlining call to a.G" "does not escape" + _ = (*a.G("").(*interface{})).(string) // ERROR "inlining call to a.G" "does not escape" + _ = (*a.G(([]byte)(nil)).(*interface{})).([]byte) // ERROR "inlining call to a.G" "does not escape" + _ = (*a.G(true).(*interface{})).(bool) // ERROR "inlining call to a.G" "does not escape" +} + +//go:noinline +func check(want, got int) { + if want != got { + println("want", want, "but got", got) + } +} diff --git a/test/fixedbugs/issue37837.go b/test/fixedbugs/issue37837.go new file mode 100644 index 0000000000..2e8abc5f05 --- /dev/null +++ b/test/fixedbugs/issue37837.go @@ -0,0 +1,7 @@ +// errorcheckandrundir -0 -m + +// Copyright 2020 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 ignored diff --git a/test/inline.go b/test/inline.go index 470414f883..d754f06e03 100644 --- a/test/inline.go +++ b/test/inline.go @@ -152,8 +152,7 @@ func switchBreak(x, y int) int { return n } -// can't currently inline functions with a type switch -func switchType(x interface{}) int { // ERROR "x does not escape" +func switchType(x interface{}) int { // ERROR "can inline switchType" "x does not escape" switch x.(type) { case int: return x.(int) -- cgit v1.3 From a444458112e4059e73c9a5a2bc5867f53bf9faa2 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Fri, 6 Nov 2020 22:46:18 -0500 Subject: cmd/compile: make sure linkname'd symbol is non-package When a variable symbol is both imported (possibly through inlining) and linkname'd, make sure its LSym is marked as non-package for symbol indexing in the object file, so it is resolved by name and dedup'd with the original definition. Fixes #42401. Change-Id: I8e90c0418c6f46a048945c5fdc06c022b77ed68d Reviewed-on: https://go-review.googlesource.com/c/go/+/268178 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Than McIntosh Reviewed-by: Jeremy Faller --- src/cmd/compile/internal/gc/gsubr.go | 6 ++++++ test/fixedbugs/issue42401.dir/a.go | 11 +++++++++++ test/fixedbugs/issue42401.dir/b.go | 24 ++++++++++++++++++++++++ test/fixedbugs/issue42401.go | 10 ++++++++++ 4 files changed, 51 insertions(+) create mode 100644 test/fixedbugs/issue42401.dir/a.go create mode 100644 test/fixedbugs/issue42401.dir/b.go create mode 100644 test/fixedbugs/issue42401.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go index 864ada1d3c..d599a383e7 100644 --- a/src/cmd/compile/internal/gc/gsubr.go +++ b/src/cmd/compile/internal/gc/gsubr.go @@ -302,6 +302,12 @@ func ggloblnod(nam *Node) { if nam.Name.LibfuzzerExtraCounter() { s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER } + if nam.Sym.Linkname != "" { + // Make sure linkname'd symbol is non-package. When a symbol is + // both imported and linkname'd, s.Pkg may not set to "_" in + // types.Sym.Linksym because LSym already exists. Set it here. + s.Pkg = "_" + } } func ggloblsym(s *obj.LSym, width int32, flags int16) { diff --git a/test/fixedbugs/issue42401.dir/a.go b/test/fixedbugs/issue42401.dir/a.go new file mode 100644 index 0000000000..75f8e7f91f --- /dev/null +++ b/test/fixedbugs/issue42401.dir/a.go @@ -0,0 +1,11 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +var s string + +func init() { s = "a" } + +func Get() string { return s } diff --git a/test/fixedbugs/issue42401.dir/b.go b/test/fixedbugs/issue42401.dir/b.go new file mode 100644 index 0000000000..a834f4efe8 --- /dev/null +++ b/test/fixedbugs/issue42401.dir/b.go @@ -0,0 +1,24 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "./a" + _ "unsafe" +) + +//go:linkname s a.s +var s string + +func main() { + if a.Get() != "a" { + panic("FAIL") + } + + s = "b" + if a.Get() != "b" { + panic("FAIL") + } +} diff --git a/test/fixedbugs/issue42401.go b/test/fixedbugs/issue42401.go new file mode 100644 index 0000000000..794d5b01b5 --- /dev/null +++ b/test/fixedbugs/issue42401.go @@ -0,0 +1,10 @@ +// rundir + +// Copyright 2020 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. + +// Issue 42401: linkname doesn't work correctly when a variable symbol +// is both imported (possibly through inlining) and linkname'd. + +package ignored -- cgit v1.3 From 92c732e901a732855f4b813e6676264421eceae9 Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 13 Nov 2020 16:54:48 -0500 Subject: cmd/compile: fix load of interface{}-typed OpIData in expand_calls In certain cases, the declkared type of an OpIData is interface{}. This was not expected (since interface{} is a pair, right?) and thus caused a crash. What is intended is that these be treated as a byteptr, so do that instead (this is what happens in 1.15). Fixes #42568. Change-Id: Id7c9e5dc2cbb5d7c71c6748832491ea62b0b339f Reviewed-on: https://go-review.googlesource.com/c/go/+/270057 Trust: David Chase Run-TryBot: David Chase Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/amd64/ssa.go | 4 ++-- src/cmd/compile/internal/ssa/expand_calls.go | 3 +++ test/fixedbugs/issue42568.go | 25 +++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 test/fixedbugs/issue42568.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 76e33a3689..5ff05a0edd 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -76,7 +76,7 @@ func storeByType(t *types.Type) obj.As { return x86.AMOVQ } } - panic("bad store type") + panic(fmt.Sprintf("bad store type %v", t)) } // moveByType returns the reg->reg move instruction of the given type. @@ -101,7 +101,7 @@ func moveByType(t *types.Type) obj.As { case 16: return x86.AMOVUPS // int128s are in SSE registers default: - panic(fmt.Sprintf("bad int register width %d:%s", t.Size(), t)) + panic(fmt.Sprintf("bad int register width %d:%v", t.Size(), t)) } } } diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index fbde19d94c..3681af6599 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -196,6 +196,9 @@ func expandCalls(f *Func) { } if leaf.Op == OpIData { leafType = removeTrivialWrapperTypes(leaf.Type) + if leafType.IsEmptyInterface() { + leafType = typ.BytePtr + } } aux := selector.Aux auxInt := selector.AuxInt + offset diff --git a/test/fixedbugs/issue42568.go b/test/fixedbugs/issue42568.go new file mode 100644 index 0000000000..834fdc58f3 --- /dev/null +++ b/test/fixedbugs/issue42568.go @@ -0,0 +1,25 @@ +// compile + +// Copyright 2020 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. + +// Ensure that late expansion correctly handles an OpIData with type interface{} + +package p + +type S struct{} + +func (S) M() {} + +type I interface { + M() +} + +func f(i I) { + o := i.(interface{}) + if _, ok := i.(*S); ok { + o = nil + } + println(o) +} -- cgit v1.3 From f2eea4c1dc37886939c010daff89c03d5a3825be Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Sat, 14 Nov 2020 13:33:32 +0100 Subject: cmd/compile: mask SLL,SRL,SRAconst shift amount mips SRA/SLL/SRL shift amounts are used mod 32; this change aligns the XXXconst rules to mask the shift amount by &31. Passes $ GOARCH=mips go build -toolexec 'toolstash -cmp' -a std $ GOARCH=mipsle go build -toolexec 'toolstash -cmp' -a std Fixes #42587 Change-Id: I6003ebd0bc500fba4cf6fb10254e1b557bf8c48f Reviewed-on: https://go-review.googlesource.com/c/go/+/270117 Trust: Alberto Donizetti Reviewed-by: Keith Randall Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/gen/MIPS.rules | 7 +++---- src/cmd/compile/internal/ssa/gen/MIPSOps.go | 6 +++--- src/cmd/compile/internal/ssa/rewriteMIPS.go | 29 ++++++----------------------- test/fixedbugs/issue42587.go | 15 +++++++++++++++ 4 files changed, 27 insertions(+), 30 deletions(-) create mode 100644 test/fixedbugs/issue42587.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/ssa/gen/MIPS.rules b/src/cmd/compile/internal/ssa/gen/MIPS.rules index aff12b4e36..7dcac9cf53 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS.rules +++ b/src/cmd/compile/internal/ssa/gen/MIPS.rules @@ -567,10 +567,9 @@ (XOR x (MOVWconst [c])) => (XORconst [c] x) (NOR x (MOVWconst [c])) => (NORconst [c] x) -(SRA x (MOVWconst [c])) && c >= 32 => (SRAconst x [31]) -(SLL x (MOVWconst [c])) => (SLLconst x [c]) -(SRL x (MOVWconst [c])) => (SRLconst x [c]) -(SRA x (MOVWconst [c])) => (SRAconst x [c]) +(SLL x (MOVWconst [c])) => (SLLconst x [c&31]) +(SRL x (MOVWconst [c])) => (SRLconst x [c&31]) +(SRA x (MOVWconst [c])) => (SRAconst x [c&31]) (SGT (MOVWconst [c]) x) => (SGTconst [c] x) (SGTU (MOVWconst [c]) x) => (SGTUconst [c] x) diff --git a/src/cmd/compile/internal/ssa/gen/MIPSOps.go b/src/cmd/compile/internal/ssa/gen/MIPSOps.go index cd7357f62b..75ab99ea26 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPSOps.go +++ b/src/cmd/compile/internal/ssa/gen/MIPSOps.go @@ -185,11 +185,11 @@ func init() { // shifts {name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << arg1, shift amount is mod 32 - {name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt + {name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt, shift amount must be 0 through 31 inclusive {name: "SRL", argLength: 2, reg: gp21, asm: "SRL"}, // arg0 >> arg1, unsigned, shift amount is mod 32 - {name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned + {name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, shift amount must be 0 through 31 inclusive {name: "SRA", argLength: 2, reg: gp21, asm: "SRA"}, // arg0 >> arg1, signed, shift amount is mod 32 - {name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed + {name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed, shift amount must be 0 through 31 inclusive {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"}, diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS.go b/src/cmd/compile/internal/ssa/rewriteMIPS.go index 970bd7b52e..cfe39d7842 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS.go @@ -4431,7 +4431,7 @@ func rewriteValueMIPS_OpMIPSSLL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (SLL x (MOVWconst [c])) - // result: (SLLconst x [c]) + // result: (SLLconst x [c&31]) for { x := v_0 if v_1.Op != OpMIPSMOVWconst { @@ -4439,7 +4439,7 @@ func rewriteValueMIPS_OpMIPSSLL(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) v.reset(OpMIPSSLLconst) - v.AuxInt = int32ToAuxInt(c) + v.AuxInt = int32ToAuxInt(c & 31) v.AddArg(x) return true } @@ -4465,24 +4465,7 @@ func rewriteValueMIPS_OpMIPSSRA(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (SRA x (MOVWconst [c])) - // cond: c >= 32 - // result: (SRAconst x [31]) - for { - x := v_0 - if v_1.Op != OpMIPSMOVWconst { - break - } - c := auxIntToInt32(v_1.AuxInt) - if !(c >= 32) { - break - } - v.reset(OpMIPSSRAconst) - v.AuxInt = int32ToAuxInt(31) - v.AddArg(x) - return true - } - // match: (SRA x (MOVWconst [c])) - // result: (SRAconst x [c]) + // result: (SRAconst x [c&31]) for { x := v_0 if v_1.Op != OpMIPSMOVWconst { @@ -4490,7 +4473,7 @@ func rewriteValueMIPS_OpMIPSSRA(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) v.reset(OpMIPSSRAconst) - v.AuxInt = int32ToAuxInt(c) + v.AuxInt = int32ToAuxInt(c & 31) v.AddArg(x) return true } @@ -4516,7 +4499,7 @@ func rewriteValueMIPS_OpMIPSSRL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (SRL x (MOVWconst [c])) - // result: (SRLconst x [c]) + // result: (SRLconst x [c&31]) for { x := v_0 if v_1.Op != OpMIPSMOVWconst { @@ -4524,7 +4507,7 @@ func rewriteValueMIPS_OpMIPSSRL(v *Value) bool { } c := auxIntToInt32(v_1.AuxInt) v.reset(OpMIPSSRLconst) - v.AuxInt = int32ToAuxInt(c) + v.AuxInt = int32ToAuxInt(c & 31) v.AddArg(x) return true } diff --git a/test/fixedbugs/issue42587.go b/test/fixedbugs/issue42587.go new file mode 100644 index 0000000000..d10ba979d5 --- /dev/null +++ b/test/fixedbugs/issue42587.go @@ -0,0 +1,15 @@ +// compile + +// Copyright 2020 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 p + +func f() { + var i, j int + _ = func() { + i = 32 + j = j>>i | len([]int{}) + } +} -- cgit v1.3 From 5b0ec1a6ac0e644c89940e0fe5f79863ad2eafaa Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 18 Nov 2020 12:08:59 -0800 Subject: cmd/compile: fix panic in field tracking logic Within the frontend, we generally don't guarantee uniqueness of anonymous types. For example, each struct type literal gets represented by its own types.Type instance. However, the field tracking code was using the struct type as a map key. This broke in golang.org/cl/256457, because that CL started changing the inlined parameter variables from using the types.Type of the declared parameter to that of the call site argument. These are always identical types (e.g., types.Identical would report true), but they can be different pointer values, causing the map lookup to fail. The easiest fix is to simply get rid of the map and instead use Node.Opt for tracking the types.Field. To mitigate against more latent field tracking failures (e.g., if any other code were to start trying to use Opt on ODOT/ODOTPTR fields), we store this field unconditionally. I also expect having the types.Field will be useful to other frontend code in the future. Finally, to make it easier to test field tracking without having to run make.bash with GOEXPERIMENT=fieldtrack, this commit adds a -d=fieldtrack flag as an alternative way to enable field tracking within the compiler. See also #42681. Fixes #42686. Change-Id: I6923d206d5e2cab1e6798cba36cae96c1eeaea55 Reviewed-on: https://go-review.googlesource.com/c/go/+/271217 Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Trust: Matthew Dempsky --- src/cmd/compile/internal/gc/main.go | 1 + src/cmd/compile/internal/gc/typecheck.go | 15 ++------------- src/cmd/compile/internal/gc/walk.go | 5 ++++- test/fixedbugs/issue42686.go | 11 +++++++++++ 4 files changed, 18 insertions(+), 14 deletions(-) create mode 100644 test/fixedbugs/issue42686.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index d1097e8236..f0a913275a 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -89,6 +89,7 @@ var debugtab = []struct { {"dwarfinl", "print information about DWARF inlined function creation", &Debug_gendwarfinl}, {"softfloat", "force compiler to emit soft-float code", &Debug_softfloat}, {"defer", "print information about defer compilation", &Debug_defer}, + {"fieldtrack", "enable fieldtracking", &objabi.Fieldtrack_enabled}, } const debugHelpHeader = `usage: -d arg[,arg]* and arg is [=] diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index cbba5ff79c..c0b05035f0 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -6,7 +6,6 @@ package gc import ( "cmd/compile/internal/types" - "cmd/internal/objabi" "fmt" "strings" ) @@ -2442,15 +2441,6 @@ func derefall(t *types.Type) *types.Type { return t } -type typeSymKey struct { - t *types.Type - s *types.Sym -} - -// dotField maps (*types.Type, *types.Sym) pairs to the corresponding struct field (*types.Type with Etype==TFIELD). -// It is a cache for use during usefield in walk.go, only enabled when field tracking. -var dotField = map[typeSymKey]*types.Field{} - func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { s := n.Sym @@ -2481,9 +2471,6 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { } n.Xoffset = f1.Offset n.Type = f1.Type - if objabi.Fieldtrack_enabled > 0 { - dotField[typeSymKey{t.Orig, s}] = f1 - } if t.IsInterface() { if n.Left.Type.IsPtr() { n.Left = nod(ODEREF, n.Left, nil) // implicitstar @@ -2492,6 +2479,8 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field { } n.Op = ODOTINTER + } else { + n.SetOpt(f1) } return f1 diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 82898c8167..a7b6e7fcb3 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -3734,10 +3734,13 @@ func usefield(n *Node) { if t.IsPtr() { t = t.Elem() } - field := dotField[typeSymKey{t.Orig, n.Sym}] + field := n.Opt().(*types.Field) if field == nil { Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym) } + if field.Sym != n.Sym || field.Offset != n.Xoffset { + Fatalf("field inconsistency: %v,%v != %v,%v", field.Sym, field.Offset, n.Sym, n.Xoffset) + } if !strings.Contains(field.Note, "go:\"track\"") { return } diff --git a/test/fixedbugs/issue42686.go b/test/fixedbugs/issue42686.go new file mode 100644 index 0000000000..962bdd35cb --- /dev/null +++ b/test/fixedbugs/issue42686.go @@ -0,0 +1,11 @@ +// compile -d=fieldtrack + +// Copyright 2020 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 p + +func a(x struct{ f int }) { _ = x.f } + +func b() { a(struct{ f int }{}) } -- cgit v1.3 From 35693d037f9d1c30d6de1fafd08e8c923a415ab8 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 18 Nov 2020 12:50:46 -0800 Subject: cmd/compile: fix miscompilation during inlining When inlining a function call expression, it's possible that the function callee subexpression has side effects that need to be preserved. This used to not be an issue, because inlining wouldn't recognize these as inlinable anyway. But golang.org/cl/266199 extended the inlining logic to recognize more cases, but did not notice that the actual inlining code was discarding side effects. Issue identified by danscales@. Fixes #42703. Change-Id: I95f8fc076b6ca4e9362e80ec26dad9d87a5bc44a Reviewed-on: https://go-review.googlesource.com/c/go/+/271219 Reviewed-by: Dan Scales Trust: Dan Scales Trust: Matthew Dempsky --- src/cmd/compile/internal/gc/inl.go | 15 +++++++++++++++ test/fixedbugs/issue42703.go | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 test/fixedbugs/issue42703.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index d49a09458c..419056985f 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -963,6 +963,21 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node { ninit := n.Ninit + // For normal function calls, the function callee expression + // may contain side effects (e.g., added by addinit during + // inlconv2expr or inlconv2list). Make sure to preserve these, + // if necessary (#42703). + if n.Op == OCALLFUNC { + callee := n.Left + for callee.Op == OCONVNOP { + ninit.AppendNodes(&callee.Ninit) + callee = callee.Left + } + if callee.Op != ONAME && callee.Op != OCLOSURE { + Fatalf("unexpected callee expression: %v", callee) + } + } + // Make temp names to use instead of the originals. inlvars := make(map[*Node]*Node) diff --git a/test/fixedbugs/issue42703.go b/test/fixedbugs/issue42703.go new file mode 100644 index 0000000000..15f7a915e6 --- /dev/null +++ b/test/fixedbugs/issue42703.go @@ -0,0 +1,19 @@ +// run + +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +var ok [2]bool + +func main() { + f()() + if !ok[0] || !ok[1] { + panic("FAIL") + } +} + +func f() func() { ok[0] = true; return g } +func g() { ok[1] = true } -- cgit v1.3 From c306fd6d0b208f67208fb4a1b5bb82e0338a080c Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Fri, 20 Nov 2020 14:09:01 +0700 Subject: cmd/compile: allow loading single field of typed-interface{} OpIData Same reason as CL 270057, but for OpLoad. Fixes #42727 Change-Id: Iebb1a8110f29427a0aed3b5e3e84f0540de3d1b7 Reviewed-on: https://go-review.googlesource.com/c/go/+/271906 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: David Chase --- src/cmd/compile/internal/ssa/expand_calls.go | 2 +- test/fixedbugs/issue42727.go | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue42727.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 3681af6599..180afab33b 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -247,7 +247,7 @@ func expandCalls(f *Func) { // i.e., the struct select is generated and remains in because it is not applied to an actual structure. // The OpLoad was created to load the single field of the IData // This case removes that StructSelect. - if leafType != selector.Type { + if leafType != selector.Type && !selector.Type.IsEmptyInterface() { // empty interface for #42727 f.Fatalf("Unexpected Load as selector, leaf=%s, selector=%s\n", leaf.LongString(), selector.LongString()) } leaf.copyOf(selector) diff --git a/test/fixedbugs/issue42727.go b/test/fixedbugs/issue42727.go new file mode 100644 index 0000000000..40081708b1 --- /dev/null +++ b/test/fixedbugs/issue42727.go @@ -0,0 +1,23 @@ +// compile + +// Copyright 2020 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. + +// Ensure that late expansion correctly handles an OpLoad with type interface{} + +package p + +type iface interface { + m() +} + +type it interface{} + +type makeIface func() iface + +func f() { + var im makeIface + e := im().(it) + _ = &e +} -- cgit v1.3 From 9ea6364a5e9f776af36604c2c20501e6d07f8467 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 20 Nov 2020 13:59:29 -0800 Subject: cmd/compile: add test for 42753 This issue was already fixed at tip. Just adding the test that failed on 1.14/1.15. Update #42753 Change-Id: I00d13ade476b9c17190d762d7fdcb30cf6c83954 Reviewed-on: https://go-review.googlesource.com/c/go/+/272029 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: David Chase --- test/fixedbugs/issue42753.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 test/fixedbugs/issue42753.go (limited to 'test/fixedbugs') diff --git a/test/fixedbugs/issue42753.go b/test/fixedbugs/issue42753.go new file mode 100644 index 0000000000..a998d1d3b3 --- /dev/null +++ b/test/fixedbugs/issue42753.go @@ -0,0 +1,13 @@ +// compile -d=ssa/check/on + +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func f() uint32 { + s := "\x01" + x := -int32(s[0]) + return uint32(x) & 0x7fffffff +} -- cgit v1.3 From 762eda346a9f4062feaa8a9fc0d17d72b11586f0 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 23 Nov 2020 15:48:37 -0800 Subject: go/types: fix incorrect string(int) conversion (regression) The bug was introduced by https://golang.org/cl/220844. Fixes #42790. Change-Id: I44d619a1a4d3f2aee1c5575d5cfddcc4ba10895f Reviewed-on: https://go-review.googlesource.com/c/go/+/272666 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Matthew Dempsky --- src/go/types/conversions.go | 16 ++++++++-------- test/fixedbugs/issue42790.go | 9 +++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 test/fixedbugs/issue42790.go (limited to 'test/fixedbugs') diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go index 0955391d7b..1cab1cc70f 100644 --- a/src/go/types/conversions.go +++ b/src/go/types/conversions.go @@ -6,7 +6,10 @@ package types -import "go/constant" +import ( + "go/constant" + "unicode" +) // Conversion type-checks the conversion T(x). // The result is in x. @@ -21,14 +24,11 @@ func (check *Checker) conversion(x *operand, T Type) { case representableConst(x.val, check, t, &x.val): ok = true case isInteger(x.typ) && isString(t): - codepoint := int64(-1) - if i, ok := constant.Int64Val(x.val); ok { - codepoint = i + codepoint := unicode.ReplacementChar + if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune { + codepoint = rune(i) } - // If codepoint < 0 the absolute value is too large (or unknown) for - // conversion. This is the same as converting any other out-of-range - // value - let string(codepoint) do the work. - x.val = constant.MakeString(string(rune(codepoint))) + x.val = constant.MakeString(string(codepoint)) ok = true } case x.convertibleTo(check, T): diff --git a/test/fixedbugs/issue42790.go b/test/fixedbugs/issue42790.go new file mode 100644 index 0000000000..d83a02247a --- /dev/null +++ b/test/fixedbugs/issue42790.go @@ -0,0 +1,9 @@ +// compile + +// Copyright 2020 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 p + +const _ = -uint(len(string(1<<32)) - len("\uFFFD")) -- cgit v1.3 From 7dc5d909fb465345bf1583eb978aaa56ca365f38 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 24 Nov 2020 00:58:00 +0700 Subject: cmd/compile: set OpLoad argument type interface{} correctly CL 271906 allows loading single field of typed-interface{} OpIData, but it does not update the corresponding selector type. So the generated OpLoad has the named type instead, prevent it from being lowered by lower pass. Fixes #42784 Change-Id: Idf32e4f711731be09d508dd712b60bc8c58309bd Reviewed-on: https://go-review.googlesource.com/c/go/+/272466 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/expand_calls.go | 3 +++ test/fixedbugs/issue42784.go | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 test/fixedbugs/issue42784.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 180afab33b..f266e49327 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -250,6 +250,9 @@ func expandCalls(f *Func) { if leafType != selector.Type && !selector.Type.IsEmptyInterface() { // empty interface for #42727 f.Fatalf("Unexpected Load as selector, leaf=%s, selector=%s\n", leaf.LongString(), selector.LongString()) } + if selector.Type.IsEmptyInterface() { + selector.Type = typ.BytePtr + } leaf.copyOf(selector) for _, s := range namedSelects[selector] { locs = append(locs, f.Names[s.locIndex]) diff --git a/test/fixedbugs/issue42784.go b/test/fixedbugs/issue42784.go new file mode 100644 index 0000000000..e2b06e9307 --- /dev/null +++ b/test/fixedbugs/issue42784.go @@ -0,0 +1,26 @@ +// compile + +// Copyright 2020 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. + +// Ensure that late expansion correctly set OpLoad argument type interface{} + +package p + +type iface interface { + m() +} + +type it interface{} + +type makeIface func() iface + +func f() { + var im makeIface + e := im().(it) + g(e) +} + +//go:noinline +func g(i it) {} -- cgit v1.3 From b94346e69bb01e1cd522ddfa9d09f41d9d4d3e98 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 26 Nov 2020 12:26:02 -0800 Subject: test: match gofrontend error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These changes match the following gofrontend error messages: blank1.go:16:1: error: may not define methods on non-local type chan/perm.go:28:9: error: expected channel chan/perm.go:29:11: error: left operand of ‘<-’ must be channel chan/perm.go:69:9: error: argument must be channel complit1.go:25:16: error: attempt to slice object that is not array, slice, or string complit1.go:26:16: error: attempt to slice object that is not array, slice, or string complit1.go:27:17: error: attempt to slice object that is not array, slice, or string complit1.go:49:41: error: may only omit types within composite literals of slice, array, or map type complit1.go:50:14: error: expected struct, slice, array, or map type for composite literal convlit.go:24:9: error: invalid type conversion (cannot use type unsafe.Pointer as type string) convlit.go:25:9: error: invalid type conversion (cannot use type unsafe.Pointer as type float64) convlit.go:26:9: error: invalid type conversion (cannot use type unsafe.Pointer as type int) ddd1.go:63:9: error: invalid use of ‘...’ calling non-variadic function fixedbugs/bug176.go:12:18: error: index expression is not integer constant fixedbugs/bug332.go:17:10: error: use of undefined type ‘T’ fixedbugs/issue4232.go:22:16: error: integer constant overflow fixedbugs/issue4232.go:33:16: error: integer constant overflow fixedbugs/issue4232.go:44:25: error: integer constant overflow fixedbugs/issue4232.go:55:16: error: integer constant overflow fixedbugs/issue4458.go:19:14: error: type has no method ‘foo’ fixedbugs/issue5172.go:24:14: error: too many expressions for struct init.go:17:9: error: reference to undefined name ‘runtime’ initializerr.go:26:29: error: duplicate value for index 1 interface/explicit.go:60:14: error: type assertion only valid for interface types label.go:64:9: error: reference to undefined label ‘go2’ label1.go:18:97: error: continue statement not within for label1.go:22:97: error: continue statement not within for label1.go:106:89: error: continue statement not within for label1.go:108:26: error: invalid continue label ‘on’ label1.go:111:118: error: break statement not within for or switch or select label1.go:113:23: error: invalid break label ‘dance’ map1.go:64:9: error: not enough arguments map1.go:65:9: error: not enough arguments map1.go:67:9: error: argument 1 must be a map method2.go:36:11: error: reference to undefined field or method ‘val’ method2.go:37:11: error: reference to undefined field or method ‘val’ method2.go:41:12: error: method requires pointer (use ‘(*T).g’) syntax/chan1.go:13:19: error: send statement used as value; use select for non-blocking send syntax/chan1.go:17:11: error: send statement used as value; use select for non-blocking send Change-Id: I98047b60a376e3d2788836300f7fcac3f2c285cb Reviewed-on: https://go-review.googlesource.com/c/go/+/273527 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- test/blank1.go | 2 +- test/chan/perm.go | 6 +++--- test/complit1.go | 10 +++++----- test/convlit.go | 6 +++--- test/ddd1.go | 2 +- test/fixedbugs/bug176.go | 2 +- test/fixedbugs/bug332.go | 2 +- test/fixedbugs/issue4232.go | 8 ++++---- test/fixedbugs/issue4458.go | 2 +- test/fixedbugs/issue5172.go | 2 +- test/init.go | 2 +- test/initializerr.go | 2 +- test/interface/explicit.go | 2 +- test/label.go | 2 +- test/label1.go | 12 ++++++------ test/map1.go | 8 ++++---- test/method2.go | 6 +++--- test/syntax/chan1.go | 4 ++-- 18 files changed, 40 insertions(+), 40 deletions(-) (limited to 'test/fixedbugs') diff --git a/test/blank1.go b/test/blank1.go index c9a8e6a290..70e01b1a30 100644 --- a/test/blank1.go +++ b/test/blank1.go @@ -13,7 +13,7 @@ var t struct { _ int } -func (x int) _() { // ERROR "cannot define new methods on non-local type" +func (x int) _() { // ERROR "methods on non-local type" println(x) } diff --git a/test/chan/perm.go b/test/chan/perm.go index 7da88bdae8..0c96d921d1 100644 --- a/test/chan/perm.go +++ b/test/chan/perm.go @@ -25,8 +25,8 @@ func main() { cs = cr // ERROR "illegal types|incompatible|cannot" var n int - <-n // ERROR "receive from non-chan" - n <- 2 // ERROR "send to non-chan" + <-n // ERROR "receive from non-chan|expected channel" + n <- 2 // ERROR "send to non-chan|must be channel" c <- 0 // ok <-c // ok @@ -66,5 +66,5 @@ func main() { close(c) close(cs) close(cr) // ERROR "receive" - close(n) // ERROR "invalid operation.*non-chan type" + close(n) // ERROR "invalid operation.*non-chan type|must be channel" } diff --git a/test/complit1.go b/test/complit1.go index eb0f920fcb..7c2a4e2996 100644 --- a/test/complit1.go +++ b/test/complit1.go @@ -22,9 +22,9 @@ var ( _ = m[0][:] // ERROR "slice of unaddressable value" _ = f()[:] // ERROR "slice of unaddressable value" - _ = 301[:] // ERROR "cannot slice" - _ = 3.1[:] // ERROR "cannot slice" - _ = true[:] // ERROR "cannot slice" + _ = 301[:] // ERROR "cannot slice|attempt to slice object that is not" + _ = 3.1[:] // ERROR "cannot slice|attempt to slice object that is not" + _ = true[:] // ERROR "cannot slice|attempt to slice object that is not" // these are okay because they are slicing a pointer to an array _ = (&[3]int{1, 2, 3})[:] @@ -46,8 +46,8 @@ var ( _ = &T{0, 0, "", nil} // ok _ = &T{i: 0, f: 0, s: "", next: {}} // ERROR "missing type in composite literal|omit types within composite literal" _ = &T{0, 0, "", {}} // ERROR "missing type in composite literal|omit types within composite literal" - _ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid composite literal type TP" - _ = &Ti{} // ERROR "invalid composite literal type Ti" + _ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid composite literal type TP|omit types within composite literal" + _ = &Ti{} // ERROR "invalid composite literal type Ti|expected.*type for composite literal" ) type M map[T]T diff --git a/test/convlit.go b/test/convlit.go index de760542da..1c66c89e88 100644 --- a/test/convlit.go +++ b/test/convlit.go @@ -21,9 +21,9 @@ var x6 = int(1e100) // ERROR "overflow" var x7 = float32(1e1000) // ERROR "overflow" // unsafe.Pointer can only convert to/from uintptr -var _ = string(unsafe.Pointer(uintptr(65))) // ERROR "convert" -var _ = float64(unsafe.Pointer(uintptr(65))) // ERROR "convert" -var _ = int(unsafe.Pointer(uintptr(65))) // ERROR "convert" +var _ = string(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion" +var _ = float64(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion" +var _ = int(unsafe.Pointer(uintptr(65))) // ERROR "convert|conversion" // implicit conversions merit scrutiny var s string diff --git a/test/ddd1.go b/test/ddd1.go index 9857814648..01b9c0eadb 100644 --- a/test/ddd1.go +++ b/test/ddd1.go @@ -60,5 +60,5 @@ func bad(args ...int) { _ = [...]byte("foo") // ERROR "[.][.][.]" _ = [...][...]int{{1,2,3},{4,5,6}} // ERROR "[.][.][.]" - Foo(x...) // ERROR "invalid use of [.][.][.] in call" + Foo(x...) // ERROR "invalid use of .*[.][.][.]" } diff --git a/test/fixedbugs/bug176.go b/test/fixedbugs/bug176.go index ea3a909747..7001dd081e 100644 --- a/test/fixedbugs/bug176.go +++ b/test/fixedbugs/bug176.go @@ -9,6 +9,6 @@ package main var x int var a = []int{ x: 1} // ERROR "constant" -var b = [...]int{x: 1} +var b = [...]int{x: 1} // GCCGO_ERROR "constant" var c = map[int]int{ x: 1} diff --git a/test/fixedbugs/bug332.go b/test/fixedbugs/bug332.go index d43c2ddcff..159c8b4e68 100644 --- a/test/fixedbugs/bug332.go +++ b/test/fixedbugs/bug332.go @@ -14,4 +14,4 @@ func main() {} // important: no newline on end of next line. // 6g used to print instead of bug332.go:111 -func (t *T) F() {} // ERROR "undefined: T" \ No newline at end of file +func (t *T) F() {} // ERROR "undefined.*T" \ No newline at end of file diff --git a/test/fixedbugs/issue4232.go b/test/fixedbugs/issue4232.go index 935f3820c6..30d132683a 100644 --- a/test/fixedbugs/issue4232.go +++ b/test/fixedbugs/issue4232.go @@ -19,7 +19,7 @@ func f() { _ = a[10:10] _ = a[9:12] // ERROR "invalid slice index 12|index out of bounds" _ = a[11:12] // ERROR "invalid slice index 11|index out of bounds" - _ = a[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" + _ = a[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds" var s []int _ = s[-1] // ERROR "invalid slice index -1|index out of bounds" @@ -30,7 +30,7 @@ func f() { _ = s[10:10] _ = s[9:12] _ = s[11:12] - _ = s[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" + _ = s[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds" const c = "foofoofoof" _ = c[-1] // ERROR "invalid string index -1|index out of bounds" @@ -41,7 +41,7 @@ func f() { _ = c[10:10] _ = c[9:12] // ERROR "invalid slice index 12|index out of bounds" _ = c[11:12] // ERROR "invalid slice index 11|index out of bounds" - _ = c[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" + _ = c[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds" var t string _ = t[-1] // ERROR "invalid string index -1|index out of bounds" @@ -52,5 +52,5 @@ func f() { _ = t[10:10] _ = t[9:12] _ = t[11:12] - _ = t[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" + _ = t[1<<100 : 1<<110] // ERROR "overflows int|integer constant overflow" "invalid slice index 1 << 100|index out of bounds" } diff --git a/test/fixedbugs/issue4458.go b/test/fixedbugs/issue4458.go index 98ffea79dc..59cfa9fcee 100644 --- a/test/fixedbugs/issue4458.go +++ b/test/fixedbugs/issue4458.go @@ -16,5 +16,5 @@ func (T) foo() {} func main() { av := T{} pav := &av - (**T).foo(&pav) // ERROR "no method foo|requires named type or pointer to named" + (**T).foo(&pav) // ERROR "no method .*foo|requires named type or pointer to named" } diff --git a/test/fixedbugs/issue5172.go b/test/fixedbugs/issue5172.go index 0339935b64..ed92ac6ff2 100644 --- a/test/fixedbugs/issue5172.go +++ b/test/fixedbugs/issue5172.go @@ -21,6 +21,6 @@ func main() { go f.bar() // ERROR "undefined" defer f.bar() // ERROR "undefined" - t := T{1} // ERROR "too many values" + t := T{1} // ERROR "too many" go t.Bar() } diff --git a/test/init.go b/test/init.go index 317f2472cb..5e182281da 100644 --- a/test/init.go +++ b/test/init.go @@ -14,6 +14,6 @@ func init() { func main() { init() // ERROR "undefined.*init" - runtime.init() // ERROR "undefined.*runtime\.init" + runtime.init() // ERROR "undefined.*runtime\.init|reference to undefined name" var _ = init // ERROR "undefined.*init" } diff --git a/test/initializerr.go b/test/initializerr.go index 990ab60f96..5e2e9a91a0 100644 --- a/test/initializerr.go +++ b/test/initializerr.go @@ -23,7 +23,7 @@ var a2 = S { Y: 3, Z: 2, Y: 3 } // ERROR "duplicate" var a3 = T { S{}, 2, 3, 4, 5, 6 } // ERROR "convert|too many" var a4 = [5]byte{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } // ERROR "index|too many" var a5 = []byte { x: 2 } // ERROR "index" -var a6 = []byte{1: 1, 2: 2, 1: 3} // ERROR "duplicate index" +var a6 = []byte{1: 1, 2: 2, 1: 3} // ERROR "duplicate" var ok1 = S { } // should be ok var ok2 = T { S: ok1 } // should be ok diff --git a/test/interface/explicit.go b/test/interface/explicit.go index 1fb3b6a05a..3f9451e8d2 100644 --- a/test/interface/explicit.go +++ b/test/interface/explicit.go @@ -57,7 +57,7 @@ func main() { // cannot type-assert non-interfaces f := 2.0 - _ = f.(int) // ERROR "non-interface type" + _ = f.(int) // ERROR "non-interface type|only valid for interface types" } diff --git a/test/label.go b/test/label.go index 11716cc2c5..7deead6fba 100644 --- a/test/label.go +++ b/test/label.go @@ -61,5 +61,5 @@ L10: goto L10 - goto go2 // ERROR "label go2 not defined" + goto go2 // ERROR "label go2 not defined|reference to undefined label .*go2" } diff --git a/test/label1.go b/test/label1.go index b2e0ef09b8..a8eaecbff2 100644 --- a/test/label1.go +++ b/test/label1.go @@ -15,11 +15,11 @@ var x int func f1() { switch x { case 1: - continue // ERROR "continue is not in a loop$" + continue // ERROR "continue is not in a loop$|continue statement not within for" } select { default: - continue // ERROR "continue is not in a loop$" + continue // ERROR "continue is not in a loop$|continue statement not within for" } } @@ -103,14 +103,14 @@ L5: } } - continue // ERROR "continue is not in a loop$" + continue // ERROR "continue is not in a loop$|continue statement not within for" for { - continue on // ERROR "continue label not defined: on" + continue on // ERROR "continue label not defined: on|invalid continue label .*on" } - break // ERROR "break is not in a loop, switch, or select" + break // ERROR "break is not in a loop, switch, or select|break statement not within for or switch or select" for { - break dance // ERROR "break label not defined: dance" + break dance // ERROR "break label not defined: dance|invalid break label .*dance" } for { diff --git a/test/map1.go b/test/map1.go index 498c2ec45b..b4aa70755f 100644 --- a/test/map1.go +++ b/test/map1.go @@ -61,8 +61,8 @@ type T8 struct { F *T7 } func main() { m := make(map[int]int) - delete() // ERROR "missing arguments" - delete(m) // ERROR "missing second \(key\) argument" + delete() // ERROR "missing arguments|not enough arguments" + delete(m) // ERROR "missing second \(key\) argument|not enough arguments" delete(m, 2, 3) // ERROR "too many arguments" - delete(1, m) // ERROR "first argument to delete must be map" -} \ No newline at end of file + delete(1, m) // ERROR "first argument to delete must be map|argument 1 must be a map" +} diff --git a/test/method2.go b/test/method2.go index a45a943156..7feb675055 100644 --- a/test/method2.go +++ b/test/method2.go @@ -33,9 +33,9 @@ var _ = (*Val).val // ERROR "method" var v Val var pv = &v -var _ = pv.val() // ERROR "pv.val undefined" -var _ = pv.val // ERROR "pv.val undefined" +var _ = pv.val() // ERROR "undefined" +var _ = pv.val // ERROR "undefined" func (t *T) g() int { return t.a } -var _ = (T).g() // ERROR "needs pointer receiver|undefined" +var _ = (T).g() // ERROR "needs pointer receiver|undefined|method requires pointer" diff --git a/test/syntax/chan1.go b/test/syntax/chan1.go index 56103d1d79..88a5b4777b 100644 --- a/test/syntax/chan1.go +++ b/test/syntax/chan1.go @@ -10,8 +10,8 @@ var c chan int var v int func main() { - if c <- v { // ERROR "cannot use c <- v as value" + if c <- v { // ERROR "cannot use c <- v as value|send statement used as value" } } -var _ = c <- v // ERROR "unexpected <-" +var _ = c <- v // ERROR "unexpected <-|send statement used as value" -- cgit v1.3 From d6abf298cf1ef56dc8cbec2ee9a18c071bb6eb3c Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 28 Nov 2020 17:51:18 -0800 Subject: test: recognize new gofrontend error message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of https://golang.org/cl/273886: fixedbugs/bug340.go:15:18: error: reference to method ‘x’ in interface with no methods For golang/go#10700 Change-Id: Id29eb0e34bbb524117614229c4c27cfd17dae286 Reviewed-on: https://go-review.googlesource.com/c/go/+/273887 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- test/fixedbugs/bug340.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/fixedbugs') diff --git a/test/fixedbugs/bug340.go b/test/fixedbugs/bug340.go index 118bbacc22..8c543c98d9 100644 --- a/test/fixedbugs/bug340.go +++ b/test/fixedbugs/bug340.go @@ -12,6 +12,6 @@ func main() { var x interface{} switch t := x.(type) { case 0: // ERROR "type" - t.x = 1 // ERROR "type interface \{\}|reference to undefined field or method" + t.x = 1 // ERROR "type interface \{\}|reference to undefined field or method|interface with no methods" } } -- cgit v1.3 From 4826abb6c2f391a9fb26c83d8ec4d6bc7cc6dc1a Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 30 Nov 2020 10:41:46 +0100 Subject: cmd/compile: do not assume TST and TEQ set V on arm These replacement rules assume that TST and TEQ set V. But TST and TEQ do not set V. This is a problem because instructions like LT are actually checking for N!=V. But with TST and TEQ not setting V, LT doesn't do anything meaningful. It's possible to construct trivial miscompilations from this, such as: package main var x = [4]int32{-0x7fffffff, 0x7fffffff, 2, 4} func main() { if x[0] > x[1] { panic("fail 1") } if x[2]&x[3] < 0 { panic("fail 2") // Fails here } } That first comparison sets V, via the CMP that subtracts the values causing the overflow. Then the second comparison operation thinks that it uses the result of TST, when it actually uses the V from CMP. Before this fix: TST R0, R1 BLT loc_6C164 After this fix: TST R0, R1 BMI loc_6C164 The BMI instruction checks the N flag, which TST sets. This commit fixes the issue by using [LG][TE]noov instead of vanilla [LG][TE], and also adds a test case for the direct issue. Fixes #42876. Change-Id: I13c62c88d18574247ad002b671b38d2d0b0fc6fa Reviewed-on: https://go-review.googlesource.com/c/go/+/274026 Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Trust: Jason A. Donenfeld --- src/cmd/compile/internal/ssa/gen/ARM.rules | 128 ++++++------ src/cmd/compile/internal/ssa/rewriteARM.go | 306 ++++++++++++++--------------- test/fixedbugs/issue42876.go | 18 ++ 3 files changed, 235 insertions(+), 217 deletions(-) create mode 100644 test/fixedbugs/issue42876.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules index 946acd4ccc..6637c6cae4 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM.rules @@ -1369,38 +1369,38 @@ (LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftLLreg x y z) yes no) (LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftRLreg x y z) yes no) (LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftRAreg x y z) yes no) -(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LT (TST x y) yes no) -(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LT (TSTconst [c] x) yes no) -(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftLL x y [c]) yes no) -(LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftRL x y [c]) yes no) -(LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftRA x y [c]) yes no) -(LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftLLreg x y z) yes no) -(LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftRLreg x y z) yes no) -(LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftRAreg x y z) yes no) -(LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LE (TST x y) yes no) -(LE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LE (TSTconst [c] x) yes no) -(LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftLL x y [c]) yes no) -(LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftRL x y [c]) yes no) -(LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftRA x y [c]) yes no) -(LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftLLreg x y z) yes no) -(LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftRLreg x y z) yes no) -(LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftRAreg x y z) yes no) -(LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LT (TEQ x y) yes no) -(LT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LT (TEQconst [c] x) yes no) -(LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftLL x y [c]) yes no) -(LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftRL x y [c]) yes no) -(LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftRA x y [c]) yes no) -(LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftLLreg x y z) yes no) -(LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftRLreg x y z) yes no) -(LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftRAreg x y z) yes no) -(LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LE (TEQ x y) yes no) -(LE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LE (TEQconst [c] x) yes no) -(LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftLL x y [c]) yes no) -(LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftRL x y [c]) yes no) -(LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftRA x y [c]) yes no) -(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftLLreg x y z) yes no) -(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftRLreg x y z) yes no) -(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftRAreg x y z) yes no) +(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LTnoov (TST x y) yes no) +(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LTnoov (TSTconst [c] x) yes no) +(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftLL x y [c]) yes no) +(LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftRL x y [c]) yes no) +(LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftRA x y [c]) yes no) +(LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftLLreg x y z) yes no) +(LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftRLreg x y z) yes no) +(LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftRAreg x y z) yes no) +(LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LEnoov (TST x y) yes no) +(LE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LEnoov (TSTconst [c] x) yes no) +(LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftLL x y [c]) yes no) +(LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftRL x y [c]) yes no) +(LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftRA x y [c]) yes no) +(LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftLLreg x y z) yes no) +(LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftRLreg x y z) yes no) +(LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftRAreg x y z) yes no) +(LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LTnoov (TEQ x y) yes no) +(LT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LTnoov (TEQconst [c] x) yes no) +(LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftLL x y [c]) yes no) +(LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftRL x y [c]) yes no) +(LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftRA x y [c]) yes no) +(LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftLLreg x y z) yes no) +(LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftRLreg x y z) yes no) +(LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftRAreg x y z) yes no) +(LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LEnoov (TEQ x y) yes no) +(LE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LEnoov (TEQconst [c] x) yes no) +(LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftLL x y [c]) yes no) +(LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftRL x y [c]) yes no) +(LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftRA x y [c]) yes no) +(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftLLreg x y z) yes no) +(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftRLreg x y z) yes no) +(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftRAreg x y z) yes no) (GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 => (GTnoov (CMP x y) yes no) (GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 => (GTnoov (CMP a (MUL x y)) yes no) (GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 => (GTnoov (CMPconst [c] x) yes no) @@ -1436,39 +1436,39 @@ (GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftLLreg x y z) yes no) (GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftRLreg x y z) yes no) (GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftRAreg x y z) yes no) -(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GT (TST x y) yes no) (GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 => (GTnoov (CMN a (MUL x y)) yes no) -(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GT (TSTconst [c] x) yes no) -(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftLL x y [c]) yes no) -(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftRL x y [c]) yes no) -(GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftRA x y [c]) yes no) -(GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftLLreg x y z) yes no) -(GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftRLreg x y z) yes no) -(GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftRAreg x y z) yes no) -(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GE (TST x y) yes no) -(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GE (TSTconst [c] x) yes no) -(GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftLL x y [c]) yes no) -(GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftRL x y [c]) yes no) -(GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftRA x y [c]) yes no) -(GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftLLreg x y z) yes no) -(GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftRLreg x y z) yes no) -(GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftRAreg x y z) yes no) -(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GT (TEQ x y) yes no) -(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GT (TEQconst [c] x) yes no) -(GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftLL x y [c]) yes no) -(GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftRL x y [c]) yes no) -(GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftRA x y [c]) yes no) -(GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftLLreg x y z) yes no) -(GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftRLreg x y z) yes no) -(GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftRAreg x y z) yes no) -(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GE (TEQ x y) yes no) -(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GE (TEQconst [c] x) yes no) -(GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftLL x y [c]) yes no) -(GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftRL x y [c]) yes no) -(GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftRA x y [c]) yes no) -(GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftLLreg x y z) yes no) -(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRLreg x y z) yes no) -(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRAreg x y z) yes no) +(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GTnoov (TST x y) yes no) +(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GTnoov (TSTconst [c] x) yes no) +(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftLL x y [c]) yes no) +(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftRL x y [c]) yes no) +(GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftRA x y [c]) yes no) +(GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftLLreg x y z) yes no) +(GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftRLreg x y z) yes no) +(GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftRAreg x y z) yes no) +(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GEnoov (TST x y) yes no) +(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GEnoov (TSTconst [c] x) yes no) +(GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftLL x y [c]) yes no) +(GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftRL x y [c]) yes no) +(GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftRA x y [c]) yes no) +(GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftLLreg x y z) yes no) +(GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftRLreg x y z) yes no) +(GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftRAreg x y z) yes no) +(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GTnoov (TEQ x y) yes no) +(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GTnoov (TEQconst [c] x) yes no) +(GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftLL x y [c]) yes no) +(GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftRL x y [c]) yes no) +(GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftRA x y [c]) yes no) +(GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftLLreg x y z) yes no) +(GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftRLreg x y z) yes no) +(GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftRAreg x y z) yes no) +(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GEnoov (TEQ x y) yes no) +(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GEnoov (TEQconst [c] x) yes no) +(GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftLL x y [c]) yes no) +(GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftRL x y [c]) yes no) +(GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftRA x y [c]) yes no) +(GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftLLreg x y z) yes no) +(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftRLreg x y z) yes no) +(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftRAreg x y z) yes no) (MOVBUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read8(sym, int64(off)))]) (MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))]) diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go index 47fd0a94cc..68495c558c 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM.go +++ b/src/cmd/compile/internal/ssa/rewriteARM.go @@ -17389,7 +17389,7 @@ func rewriteBlockARM(b *Block) bool { } // match: (GE (CMPconst [0] l:(AND x y)) yes no) // cond: l.Uses==1 - // result: (GE (TST x y) yes no) + // result: (GEnoov (TST x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17410,14 +17410,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } break } // match: (GE (CMPconst [0] l:(ANDconst [c] x)) yes no) // cond: l.Uses==1 - // result: (GE (TSTconst [c] x) yes no) + // result: (GEnoov (TSTconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17435,12 +17435,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg(x) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (TSTshiftLL x y [c]) yes no) + // result: (GEnoov (TSTshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17459,12 +17459,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (TSTshiftRL x y [c]) yes no) + // result: (GEnoov (TSTshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17483,12 +17483,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (TSTshiftRA x y [c]) yes no) + // result: (GEnoov (TSTshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17507,12 +17507,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (TSTshiftLLreg x y z) yes no) + // result: (GEnoov (TSTshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17530,12 +17530,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (TSTshiftRLreg x y z) yes no) + // result: (GEnoov (TSTshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17553,12 +17553,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (TSTshiftRAreg x y z) yes no) + // result: (GEnoov (TSTshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17576,12 +17576,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(XOR x y)) yes no) // cond: l.Uses==1 - // result: (GE (TEQ x y) yes no) + // result: (GEnoov (TEQ x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17602,14 +17602,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } break } // match: (GE (CMPconst [0] l:(XORconst [c] x)) yes no) // cond: l.Uses==1 - // result: (GE (TEQconst [c] x) yes no) + // result: (GEnoov (TEQconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17627,12 +17627,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg(x) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (TEQshiftLL x y [c]) yes no) + // result: (GEnoov (TEQshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17651,12 +17651,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (TEQshiftRL x y [c]) yes no) + // result: (GEnoov (TEQshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17675,12 +17675,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (GE (TEQshiftRA x y [c]) yes no) + // result: (GEnoov (TEQshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17699,12 +17699,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (TEQshiftLLreg x y z) yes no) + // result: (GEnoov (TEQshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17722,12 +17722,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (TEQshiftRLreg x y z) yes no) + // result: (GEnoov (TEQshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17745,12 +17745,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } // match: (GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (GE (TEQshiftRAreg x y z) yes no) + // result: (GEnoov (TEQshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -17768,7 +17768,7 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGE, v0) + b.resetWithControl(BlockARMGEnoov, v0) return true } case BlockARMGEnoov: @@ -18278,9 +18278,34 @@ func rewriteBlockARM(b *Block) bool { b.resetWithControl(BlockARMGTnoov, v0) return true } + // match: (GT (CMPconst [0] l:(MULA x y a)) yes no) + // cond: l.Uses==1 + // result: (GTnoov (CMN a (MUL x y)) yes no) + for b.Controls[0].Op == OpARMCMPconst { + v_0 := b.Controls[0] + if auxIntToInt32(v_0.AuxInt) != 0 { + break + } + l := v_0.Args[0] + if l.Op != OpARMMULA { + break + } + a := l.Args[2] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) + v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type) + v1.AddArg2(x, y) + v0.AddArg2(a, v1) + b.resetWithControl(BlockARMGTnoov, v0) + return true + } // match: (GT (CMPconst [0] l:(AND x y)) yes no) // cond: l.Uses==1 - // result: (GT (TST x y) yes no) + // result: (GTnoov (TST x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18301,39 +18326,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } break } - // match: (GT (CMPconst [0] l:(MULA x y a)) yes no) - // cond: l.Uses==1 - // result: (GTnoov (CMN a (MUL x y)) yes no) - for b.Controls[0].Op == OpARMCMPconst { - v_0 := b.Controls[0] - if auxIntToInt32(v_0.AuxInt) != 0 { - break - } - l := v_0.Args[0] - if l.Op != OpARMMULA { - break - } - a := l.Args[2] - x := l.Args[0] - y := l.Args[1] - if !(l.Uses == 1) { - break - } - v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags) - v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type) - v1.AddArg2(x, y) - v0.AddArg2(a, v1) - b.resetWithControl(BlockARMGTnoov, v0) - return true - } // match: (GT (CMPconst [0] l:(ANDconst [c] x)) yes no) // cond: l.Uses==1 - // result: (GT (TSTconst [c] x) yes no) + // result: (GTnoov (TSTconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18351,12 +18351,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg(x) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (TSTshiftLL x y [c]) yes no) + // result: (GTnoov (TSTshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18375,12 +18375,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (TSTshiftRL x y [c]) yes no) + // result: (GTnoov (TSTshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18399,12 +18399,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (TSTshiftRA x y [c]) yes no) + // result: (GTnoov (TSTshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18423,12 +18423,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (TSTshiftLLreg x y z) yes no) + // result: (GTnoov (TSTshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18446,12 +18446,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (TSTshiftRLreg x y z) yes no) + // result: (GTnoov (TSTshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18469,12 +18469,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (TSTshiftRAreg x y z) yes no) + // result: (GTnoov (TSTshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18492,12 +18492,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(XOR x y)) yes no) // cond: l.Uses==1 - // result: (GT (TEQ x y) yes no) + // result: (GTnoov (TEQ x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18518,14 +18518,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } break } // match: (GT (CMPconst [0] l:(XORconst [c] x)) yes no) // cond: l.Uses==1 - // result: (GT (TEQconst [c] x) yes no) + // result: (GTnoov (TEQconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18543,12 +18543,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg(x) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (TEQshiftLL x y [c]) yes no) + // result: (GTnoov (TEQshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18567,12 +18567,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (TEQshiftRL x y [c]) yes no) + // result: (GTnoov (TEQshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18591,12 +18591,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (GT (TEQshiftRA x y [c]) yes no) + // result: (GTnoov (TEQshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18615,12 +18615,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (TEQshiftLLreg x y z) yes no) + // result: (GTnoov (TEQshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18638,12 +18638,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (TEQshiftRLreg x y z) yes no) + // result: (GTnoov (TEQshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18661,12 +18661,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } // match: (GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (GT (TEQshiftRAreg x y z) yes no) + // result: (GTnoov (TEQshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -18684,7 +18684,7 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMGT, v0) + b.resetWithControl(BlockARMGTnoov, v0) return true } case BlockARMGTnoov: @@ -19312,7 +19312,7 @@ func rewriteBlockARM(b *Block) bool { } // match: (LE (CMPconst [0] l:(AND x y)) yes no) // cond: l.Uses==1 - // result: (LE (TST x y) yes no) + // result: (LEnoov (TST x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19333,14 +19333,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } break } // match: (LE (CMPconst [0] l:(ANDconst [c] x)) yes no) // cond: l.Uses==1 - // result: (LE (TSTconst [c] x) yes no) + // result: (LEnoov (TSTconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19358,12 +19358,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg(x) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (TSTshiftLL x y [c]) yes no) + // result: (LEnoov (TSTshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19382,12 +19382,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (TSTshiftRL x y [c]) yes no) + // result: (LEnoov (TSTshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19406,12 +19406,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (TSTshiftRA x y [c]) yes no) + // result: (LEnoov (TSTshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19430,12 +19430,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (TSTshiftLLreg x y z) yes no) + // result: (LEnoov (TSTshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19453,12 +19453,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (TSTshiftRLreg x y z) yes no) + // result: (LEnoov (TSTshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19476,12 +19476,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (TSTshiftRAreg x y z) yes no) + // result: (LEnoov (TSTshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19499,12 +19499,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(XOR x y)) yes no) // cond: l.Uses==1 - // result: (LE (TEQ x y) yes no) + // result: (LEnoov (TEQ x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19525,14 +19525,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } break } // match: (LE (CMPconst [0] l:(XORconst [c] x)) yes no) // cond: l.Uses==1 - // result: (LE (TEQconst [c] x) yes no) + // result: (LEnoov (TEQconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19550,12 +19550,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg(x) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (TEQshiftLL x y [c]) yes no) + // result: (LEnoov (TEQshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19574,12 +19574,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (TEQshiftRL x y [c]) yes no) + // result: (LEnoov (TEQshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19598,12 +19598,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (LE (TEQshiftRA x y [c]) yes no) + // result: (LEnoov (TEQshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19622,12 +19622,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (TEQshiftLLreg x y z) yes no) + // result: (LEnoov (TEQshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19645,12 +19645,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (TEQshiftRLreg x y z) yes no) + // result: (LEnoov (TEQshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19668,12 +19668,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } // match: (LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (LE (TEQshiftRAreg x y z) yes no) + // result: (LEnoov (TEQshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -19691,7 +19691,7 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLE, v0) + b.resetWithControl(BlockARMLEnoov, v0) return true } case BlockARMLEnoov: @@ -20228,7 +20228,7 @@ func rewriteBlockARM(b *Block) bool { } // match: (LT (CMPconst [0] l:(AND x y)) yes no) // cond: l.Uses==1 - // result: (LT (TST x y) yes no) + // result: (LTnoov (TST x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20249,14 +20249,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTST, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } break } // match: (LT (CMPconst [0] l:(ANDconst [c] x)) yes no) // cond: l.Uses==1 - // result: (LT (TSTconst [c] x) yes no) + // result: (LTnoov (TSTconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20274,12 +20274,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTconst, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg(x) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (TSTshiftLL x y [c]) yes no) + // result: (LTnoov (TSTshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20298,12 +20298,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (TSTshiftRL x y [c]) yes no) + // result: (LTnoov (TSTshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20322,12 +20322,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (TSTshiftRA x y [c]) yes no) + // result: (LTnoov (TSTshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20346,12 +20346,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRA, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (TSTshiftLLreg x y z) yes no) + // result: (LTnoov (TSTshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20369,12 +20369,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (TSTshiftRLreg x y z) yes no) + // result: (LTnoov (TSTshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20392,12 +20392,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (TSTshiftRAreg x y z) yes no) + // result: (LTnoov (TSTshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20415,12 +20415,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTSTshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(XOR x y)) yes no) // cond: l.Uses==1 - // result: (LT (TEQ x y) yes no) + // result: (LTnoov (TEQ x y) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20441,14 +20441,14 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQ, types.TypeFlags) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } break } // match: (LT (CMPconst [0] l:(XORconst [c] x)) yes no) // cond: l.Uses==1 - // result: (LT (TEQconst [c] x) yes no) + // result: (LTnoov (TEQconst [c] x) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20466,12 +20466,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQconst, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg(x) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (TEQshiftLL x y [c]) yes no) + // result: (LTnoov (TEQshiftLL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20490,12 +20490,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (TEQshiftRL x y [c]) yes no) + // result: (LTnoov (TEQshiftRL x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20514,12 +20514,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRL, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) // cond: l.Uses==1 - // result: (LT (TEQshiftRA x y [c]) yes no) + // result: (LTnoov (TEQshiftRA x y [c]) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20538,12 +20538,12 @@ func rewriteBlockARM(b *Block) bool { v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRA, types.TypeFlags) v0.AuxInt = int32ToAuxInt(c) v0.AddArg2(x, y) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (TEQshiftLLreg x y z) yes no) + // result: (LTnoov (TEQshiftLLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20561,12 +20561,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftLLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (TEQshiftRLreg x y z) yes no) + // result: (LTnoov (TEQshiftRLreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20584,12 +20584,12 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRLreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } // match: (LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) // cond: l.Uses==1 - // result: (LT (TEQshiftRAreg x y z) yes no) + // result: (LTnoov (TEQshiftRAreg x y z) yes no) for b.Controls[0].Op == OpARMCMPconst { v_0 := b.Controls[0] if auxIntToInt32(v_0.AuxInt) != 0 { @@ -20607,7 +20607,7 @@ func rewriteBlockARM(b *Block) bool { } v0 := b.NewValue0(v_0.Pos, OpARMTEQshiftRAreg, types.TypeFlags) v0.AddArg3(x, y, z) - b.resetWithControl(BlockARMLT, v0) + b.resetWithControl(BlockARMLTnoov, v0) return true } case BlockARMLTnoov: diff --git a/test/fixedbugs/issue42876.go b/test/fixedbugs/issue42876.go new file mode 100644 index 0000000000..67cf4919ac --- /dev/null +++ b/test/fixedbugs/issue42876.go @@ -0,0 +1,18 @@ +// run + +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +var x = [4]int32{-0x7fffffff, 0x7fffffff, 2, 4} + +func main() { + if x[0] > x[1] { + panic("fail 1") + } + if x[2]&x[3] < 0 { + panic("fail 2") // Fails here + } +} -- cgit v1.3 From bacb307b80747deaf6a017f5b3cee4e3cb115f61 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 3 Dec 2020 12:02:00 -0800 Subject: test: match gofrontend error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixedbugs/bug487.go:17:17: error: function result count mismatch fixedbugs/bug487.go:18:16: error: function result count mismatch fixedbugs/issue6977.go:37:26: error: duplicate method ‘m’ fixedbugs/issue6977.go:38:21: error: duplicate method ‘m’ fixedbugs/issue6977.go:39:26: error: duplicate method ‘m’ fixedbugs/issue6977.go:40:21: error: duplicate method ‘m’ Change-Id: Ie3c8a4650cd8f4c239bdceac25dc188a6a50ca34 Reviewed-on: https://go-review.googlesource.com/c/go/+/275178 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Cherry Zhang Reviewed-by: Than McIntosh --- test/fixedbugs/bug487.go | 4 ++-- test/fixedbugs/issue6977.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'test/fixedbugs') diff --git a/test/fixedbugs/bug487.go b/test/fixedbugs/bug487.go index ab61a19a94..e60af6c8e2 100644 --- a/test/fixedbugs/bug487.go +++ b/test/fixedbugs/bug487.go @@ -14,8 +14,8 @@ func G() (int, int, int) { } func F() { - a, b := G() // ERROR "assignment mismatch" - a, b = G() // ERROR "assignment mismatch" + a, b := G() // ERROR "mismatch" + a, b = G() // ERROR "mismatch" _, _ = a, b } diff --git a/test/fixedbugs/issue6977.go b/test/fixedbugs/issue6977.go index 0f657eec41..4525e406b8 100644 --- a/test/fixedbugs/issue6977.go +++ b/test/fixedbugs/issue6977.go @@ -34,7 +34,7 @@ type U3 interface { M; m() } type U4 interface { M; M; M } type U5 interface { U1; U2; U3; U4 } -type U6 interface { m(); m() } // ERROR "duplicate method m" -type U7 interface { M32; m() } // ERROR "duplicate method m" -type U8 interface { m(); M32 } // ERROR "duplicate method m" -type U9 interface { M32; M64 } // ERROR "duplicate method m" +type U6 interface { m(); m() } // ERROR "duplicate method .*m" +type U7 interface { M32; m() } // ERROR "duplicate method .*m" +type U8 interface { m(); M32 } // ERROR "duplicate method .*m" +type U9 interface { M32; M64 } // ERROR "duplicate method .*m" -- cgit v1.3 From 37a32a1833a6e55baaa8d971406094148e42f7d1 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Thu, 3 Dec 2020 13:32:11 -0500 Subject: cmd/compile: make sure address of offset(SP) is rematerializeable An address of offset(SP) may point to the callee args area, and may be used to move things into/out of the args/results. If an address like that is spilled and picked up by the GC, it may hold an arg/result live in the callee, which may not actually be live (e.g. a result not initialized at function entry). Make sure they are rematerializeable, so they are always short-lived and never picked up by the GC. This CL changes 386, PPC64, and Wasm. On AMD64 we already have the rule (line 2159). On other architectures, we already have similar rules like (OffPtr [off] ptr:(SP)) => (MOVDaddr [int32(off)] ptr) to avoid this problem. (Probably me in the past had run into this...) Fixes #42944. Change-Id: Id2ec73ac08f8df1829a9a7ceb8f749d67fe86d1e Reviewed-on: https://go-review.googlesource.com/c/go/+/275174 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/gen/386.rules | 1 + src/cmd/compile/internal/ssa/gen/PPC64.rules | 1 + src/cmd/compile/internal/ssa/gen/Wasm.rules | 1 + src/cmd/compile/internal/ssa/rewrite386.go | 13 +++++++++++++ src/cmd/compile/internal/ssa/rewritePPC64.go | 14 ++++++++++++++ src/cmd/compile/internal/ssa/rewriteWasm.go | 14 ++++++++++++++ src/cmd/compile/internal/wasm/ssa.go | 6 ++++++ test/fixedbugs/issue42944.go | 24 ++++++++++++++++++++++++ 8 files changed, 74 insertions(+) create mode 100644 test/fixedbugs/issue42944.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules index 537705c681..fbc12fd672 100644 --- a/src/cmd/compile/internal/ssa/gen/386.rules +++ b/src/cmd/compile/internal/ssa/gen/386.rules @@ -531,6 +531,7 @@ // fold ADDL into LEAL (ADDLconst [c] (LEAL [d] {s} x)) && is32Bit(int64(c)+int64(d)) => (LEAL [c+d] {s} x) (LEAL [c] {s} (ADDLconst [d] x)) && is32Bit(int64(c)+int64(d)) => (LEAL [c+d] {s} x) +(ADDLconst [c] x:(SP)) => (LEAL [c] x) // so it is rematerializeable (LEAL [c] {s} (ADDL x y)) && x.Op != OpSB && y.Op != OpSB => (LEAL1 [c] {s} x y) (ADDL x (LEAL [c] {s} y)) && x.Op != OpSB && y.Op != OpSB => (LEAL1 [c] {s} x y) diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules index 31b186d167..c064046172 100644 --- a/src/cmd/compile/internal/ssa/gen/PPC64.rules +++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules @@ -845,6 +845,7 @@ (SUB x (MOVDconst [c])) && is32Bit(-c) => (ADDconst [-c] x) (ADDconst [c] (MOVDaddr [d] {sym} x)) && is32Bit(c+int64(d)) => (MOVDaddr [int32(c+int64(d))] {sym} x) +(ADDconst [c] x:(SP)) && is32Bit(c) => (MOVDaddr [int32(c)] x) // so it is rematerializeable (MULL(W|D) x (MOVDconst [c])) && is16Bit(c) => (MULL(W|D)const [int32(c)] x) diff --git a/src/cmd/compile/internal/ssa/gen/Wasm.rules b/src/cmd/compile/internal/ssa/gen/Wasm.rules index ea12c5d617..fc45cd3ed5 100644 --- a/src/cmd/compile/internal/ssa/gen/Wasm.rules +++ b/src/cmd/compile/internal/ssa/gen/Wasm.rules @@ -399,6 +399,7 @@ // folding offset into address (I64AddConst [off] (LoweredAddr {sym} [off2] base)) && isU32Bit(off+int64(off2)) => (LoweredAddr {sym} [int32(off)+off2] base) +(I64AddConst [off] x:(SP)) && isU32Bit(off) => (LoweredAddr [int32(off)] x) // so it is rematerializeable // transforming readonly globals into constants (I64Load [off] (LoweredAddr {sym} [off2] (SB)) _) && symIsRO(sym) && isU32Bit(off+int64(off2)) => (I64Const [int64(read64(sym, off+int64(off2), config.ctxt.Arch.ByteOrder))]) diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go index eca4817b9b..2acdccd568 100644 --- a/src/cmd/compile/internal/ssa/rewrite386.go +++ b/src/cmd/compile/internal/ssa/rewrite386.go @@ -1027,6 +1027,19 @@ func rewriteValue386_Op386ADDLconst(v *Value) bool { v.AddArg(x) return true } + // match: (ADDLconst [c] x:(SP)) + // result: (LEAL [c] x) + for { + c := auxIntToInt32(v.AuxInt) + x := v_0 + if x.Op != OpSP { + break + } + v.reset(Op386LEAL) + v.AuxInt = int32ToAuxInt(c) + v.AddArg(x) + return true + } // match: (ADDLconst [c] (LEAL1 [d] {s} x y)) // cond: is32Bit(int64(c)+int64(d)) // result: (LEAL1 [c+d] {s} x y) diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go index 7d4cf73fd8..455f9b1388 100644 --- a/src/cmd/compile/internal/ssa/rewritePPC64.go +++ b/src/cmd/compile/internal/ssa/rewritePPC64.go @@ -4195,6 +4195,20 @@ func rewriteValuePPC64_OpPPC64ADDconst(v *Value) bool { v.AddArg(x) return true } + // match: (ADDconst [c] x:(SP)) + // cond: is32Bit(c) + // result: (MOVDaddr [int32(c)] x) + for { + c := auxIntToInt64(v.AuxInt) + x := v_0 + if x.Op != OpSP || !(is32Bit(c)) { + break + } + v.reset(OpPPC64MOVDaddr) + v.AuxInt = int32ToAuxInt(int32(c)) + v.AddArg(x) + return true + } // match: (ADDconst [c] (SUBFCconst [d] x)) // cond: is32Bit(c+d) // result: (SUBFCconst [c+d] x) diff --git a/src/cmd/compile/internal/ssa/rewriteWasm.go b/src/cmd/compile/internal/ssa/rewriteWasm.go index 52b6f6bfc7..c8ecefc736 100644 --- a/src/cmd/compile/internal/ssa/rewriteWasm.go +++ b/src/cmd/compile/internal/ssa/rewriteWasm.go @@ -3693,6 +3693,20 @@ func rewriteValueWasm_OpWasmI64AddConst(v *Value) bool { v.AddArg(base) return true } + // match: (I64AddConst [off] x:(SP)) + // cond: isU32Bit(off) + // result: (LoweredAddr [int32(off)] x) + for { + off := auxIntToInt64(v.AuxInt) + x := v_0 + if x.Op != OpSP || !(isU32Bit(off)) { + break + } + v.reset(OpWasmLoweredAddr) + v.AuxInt = int32ToAuxInt(int32(off)) + v.AddArg(x) + return true + } return false } func rewriteValueWasm_OpWasmI64And(v *Value) bool { diff --git a/src/cmd/compile/internal/wasm/ssa.go b/src/cmd/compile/internal/wasm/ssa.go index a36fbca4e0..9c9f6edc5f 100644 --- a/src/cmd/compile/internal/wasm/ssa.go +++ b/src/cmd/compile/internal/wasm/ssa.go @@ -230,6 +230,12 @@ func ssaGenValueOnStack(s *gc.SSAGenState, v *ssa.Value, extend bool) { } case ssa.OpWasmLoweredAddr: + if v.Aux == nil { // address of off(SP), no symbol + getValue64(s, v.Args[0]) + i64Const(s, v.AuxInt) + s.Prog(wasm.AI64Add) + break + } p := s.Prog(wasm.AGet) p.From.Type = obj.TYPE_ADDR switch v.Aux.(type) { diff --git a/test/fixedbugs/issue42944.go b/test/fixedbugs/issue42944.go new file mode 100644 index 0000000000..bb947bc609 --- /dev/null +++ b/test/fixedbugs/issue42944.go @@ -0,0 +1,24 @@ +// errorcheck -0 -live + +// Copyright 2020 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. + +// Issue 42944: address of callee args area should only be short-lived +// and never across a call. + +package p + +type T [10]int // trigger DUFFCOPY when passing by value, so it uses the address + +func F() { + var x T + var i int + for { + x = G(i) // no autotmp live at this and next calls + H(i, x) + } +} + +func G(int) T +func H(int, T) -- cgit v1.3 From 9c0e2db051093767526c96cbe02d3c3b7d28f770 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 5 Dec 2020 08:08:47 -0800 Subject: test: add new test that gofrontend failed to handle The gofrontend code would in some circumstances incorrectly generate a type descriptor for an alias type, causing the type to fail to be equal to the unaliased type. Change-Id: I47d33b0bfde3c72a9a186049539732bdd5a6a96e Reviewed-on: https://go-review.googlesource.com/c/go/+/275632 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- test/fixedbugs/bug510.dir/a.go | 13 +++++++++++++ test/fixedbugs/bug510.dir/b.go | 14 ++++++++++++++ test/fixedbugs/bug510.go | 9 +++++++++ 3 files changed, 36 insertions(+) create mode 100644 test/fixedbugs/bug510.dir/a.go create mode 100644 test/fixedbugs/bug510.dir/b.go create mode 100644 test/fixedbugs/bug510.go (limited to 'test/fixedbugs') diff --git a/test/fixedbugs/bug510.dir/a.go b/test/fixedbugs/bug510.dir/a.go new file mode 100644 index 0000000000..db1cfef366 --- /dev/null +++ b/test/fixedbugs/bug510.dir/a.go @@ -0,0 +1,13 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +import "reflect" + +type A = map[int] bool + +func F() interface{} { + return reflect.New(reflect.TypeOf((*A)(nil))).Elem().Interface() +} diff --git a/test/fixedbugs/bug510.dir/b.go b/test/fixedbugs/bug510.dir/b.go new file mode 100644 index 0000000000..56b0201858 --- /dev/null +++ b/test/fixedbugs/bug510.dir/b.go @@ -0,0 +1,14 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "./a" + +func main() { + _, ok := a.F().(*map[int]bool) + if !ok { + panic("bad type") + } +} diff --git a/test/fixedbugs/bug510.go b/test/fixedbugs/bug510.go new file mode 100644 index 0000000000..8a6da5dfd6 --- /dev/null +++ b/test/fixedbugs/bug510.go @@ -0,0 +1,9 @@ +// rundir + +// Copyright 2020 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. + +// Gccgo confused type descriptors for aliases. + +package ignored -- cgit v1.3 From 6c64b6db6802818dd9a4789cdd564f19b70b6b4c Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 9 Dec 2020 08:27:54 -0800 Subject: cmd/compile: don't constant fold divide by zero It just makes the compiler crash. Oops. Fixes #43099 Change-Id: Id996c14799c1a5d0063ecae3b8770568161c2440 Reviewed-on: https://go-review.googlesource.com/c/go/+/276652 Trust: Keith Randall Run-TryBot: Keith Randall TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/ssa/gen/ARM.rules | 4 ++-- src/cmd/compile/internal/ssa/gen/ARM64.rules | 16 ++++++------- src/cmd/compile/internal/ssa/gen/MIPS.rules | 8 +++---- src/cmd/compile/internal/ssa/gen/MIPS64.rules | 8 +++---- src/cmd/compile/internal/ssa/rewriteARM.go | 8 +++++++ src/cmd/compile/internal/ssa/rewriteARM64.go | 32 +++++++++++++++++++++++++ src/cmd/compile/internal/ssa/rewriteMIPS.go | 16 +++++++++++++ src/cmd/compile/internal/ssa/rewriteMIPS64.go | 16 +++++++++++++ test/fixedbugs/issue43099.go | 34 +++++++++++++++++++++++++++ 9 files changed, 124 insertions(+), 18 deletions(-) create mode 100644 test/fixedbugs/issue43099.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules index 6637c6cae4..11c36b5da3 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM.rules @@ -760,8 +760,8 @@ (MUL (MOVWconst [c]) (MOVWconst [d])) => (MOVWconst [c*d]) (MULA (MOVWconst [c]) (MOVWconst [d]) a) => (ADDconst [c*d] a) (MULS (MOVWconst [c]) (MOVWconst [d]) a) => (SUBconst [c*d] a) -(Select0 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) => (MOVWconst [int32(uint32(c)/uint32(d))]) -(Select1 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) => (MOVWconst [int32(uint32(c)%uint32(d))]) +(Select0 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) && d != 0 => (MOVWconst [int32(uint32(c)/uint32(d))]) +(Select1 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) && d != 0 => (MOVWconst [int32(uint32(c)%uint32(d))]) (ANDconst [c] (MOVWconst [d])) => (MOVWconst [c&d]) (ANDconst [c] (ANDconst [d] x)) => (ANDconst [c&d] x) (ORconst [c] (MOVWconst [d])) => (MOVWconst [c|d]) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index 9edc0c94b0..3f4d0c1c52 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -1372,14 +1372,14 @@ (MADDW a (MOVDconst [c]) (MOVDconst [d])) => (ADDconst [int64(int32(c)*int32(d))] a) (MSUB a (MOVDconst [c]) (MOVDconst [d])) => (SUBconst [c*d] a) (MSUBW a (MOVDconst [c]) (MOVDconst [d])) => (SUBconst [int64(int32(c)*int32(d))] a) -(DIV (MOVDconst [c]) (MOVDconst [d])) => (MOVDconst [c/d]) -(UDIV (MOVDconst [c]) (MOVDconst [d])) => (MOVDconst [int64(uint64(c)/uint64(d))]) -(DIVW (MOVDconst [c]) (MOVDconst [d])) => (MOVDconst [int64(int32(c)/int32(d))]) -(UDIVW (MOVDconst [c]) (MOVDconst [d])) => (MOVDconst [int64(uint32(c)/uint32(d))]) -(MOD (MOVDconst [c]) (MOVDconst [d])) => (MOVDconst [c%d]) -(UMOD (MOVDconst [c]) (MOVDconst [d])) => (MOVDconst [int64(uint64(c)%uint64(d))]) -(MODW (MOVDconst [c]) (MOVDconst [d])) => (MOVDconst [int64(int32(c)%int32(d))]) -(UMODW (MOVDconst [c]) (MOVDconst [d])) => (MOVDconst [int64(uint32(c)%uint32(d))]) +(DIV (MOVDconst [c]) (MOVDconst [d])) && d != 0 => (MOVDconst [c/d]) +(UDIV (MOVDconst [c]) (MOVDconst [d])) && d != 0 => (MOVDconst [int64(uint64(c)/uint64(d))]) +(DIVW (MOVDconst [c]) (MOVDconst [d])) && d != 0 => (MOVDconst [int64(int32(c)/int32(d))]) +(UDIVW (MOVDconst [c]) (MOVDconst [d])) && d != 0 => (MOVDconst [int64(uint32(c)/uint32(d))]) +(MOD (MOVDconst [c]) (MOVDconst [d])) && d != 0 => (MOVDconst [c%d]) +(UMOD (MOVDconst [c]) (MOVDconst [d])) && d != 0 => (MOVDconst [int64(uint64(c)%uint64(d))]) +(MODW (MOVDconst [c]) (MOVDconst [d])) && d != 0 => (MOVDconst [int64(int32(c)%int32(d))]) +(UMODW (MOVDconst [c]) (MOVDconst [d])) && d != 0 => (MOVDconst [int64(uint32(c)%uint32(d))]) (ANDconst [c] (MOVDconst [d])) => (MOVDconst [c&d]) (ANDconst [c] (ANDconst [d] x)) => (ANDconst [c&d] x) (ANDconst [c] (MOVWUreg x)) => (ANDconst [c&(1<<32-1)] x) diff --git a/src/cmd/compile/internal/ssa/gen/MIPS.rules b/src/cmd/compile/internal/ssa/gen/MIPS.rules index 470cc66869..8ad2c90ac3 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS.rules +++ b/src/cmd/compile/internal/ssa/gen/MIPS.rules @@ -626,10 +626,10 @@ (MUL (MOVWconst [c]) (MOVWconst [d])) => (MOVWconst [c*d]) (Select1 (MULTU (MOVWconst [c]) (MOVWconst [d]))) => (MOVWconst [int32(uint32(c)*uint32(d))]) (Select0 (MULTU (MOVWconst [c]) (MOVWconst [d]))) => (MOVWconst [int32((int64(uint32(c))*int64(uint32(d)))>>32)]) -(Select1 (DIV (MOVWconst [c]) (MOVWconst [d]))) => (MOVWconst [c/d]) -(Select1 (DIVU (MOVWconst [c]) (MOVWconst [d]))) => (MOVWconst [int32(uint32(c)/uint32(d))]) -(Select0 (DIV (MOVWconst [c]) (MOVWconst [d]))) => (MOVWconst [c%d]) -(Select0 (DIVU (MOVWconst [c]) (MOVWconst [d]))) => (MOVWconst [int32(uint32(c)%uint32(d))]) +(Select1 (DIV (MOVWconst [c]) (MOVWconst [d]))) && d != 0 => (MOVWconst [c/d]) +(Select1 (DIVU (MOVWconst [c]) (MOVWconst [d]))) && d != 0 => (MOVWconst [int32(uint32(c)/uint32(d))]) +(Select0 (DIV (MOVWconst [c]) (MOVWconst [d]))) && d != 0 => (MOVWconst [c%d]) +(Select0 (DIVU (MOVWconst [c]) (MOVWconst [d]))) && d != 0 => (MOVWconst [int32(uint32(c)%uint32(d))]) (ANDconst [c] (MOVWconst [d])) => (MOVWconst [c&d]) (ANDconst [c] (ANDconst [d] x)) => (ANDconst [c&d] x) (ORconst [c] (MOVWconst [d])) => (MOVWconst [c|d]) diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64.rules b/src/cmd/compile/internal/ssa/gen/MIPS64.rules index 9af0f93333..088c9b1ac4 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS64.rules +++ b/src/cmd/compile/internal/ssa/gen/MIPS64.rules @@ -617,10 +617,10 @@ (SRLVconst [c] (MOVVconst [d])) => (MOVVconst [int64(uint64(d)>>uint64(c))]) (SRAVconst [c] (MOVVconst [d])) => (MOVVconst [d>>uint64(c)]) (Select1 (MULVU (MOVVconst [c]) (MOVVconst [d]))) => (MOVVconst [c*d]) -(Select1 (DIVV (MOVVconst [c]) (MOVVconst [d]))) => (MOVVconst [c/d]) -(Select1 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) => (MOVVconst [int64(uint64(c)/uint64(d))]) -(Select0 (DIVV (MOVVconst [c]) (MOVVconst [d]))) => (MOVVconst [c%d]) // mod -(Select0 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) => (MOVVconst [int64(uint64(c)%uint64(d))]) // mod +(Select1 (DIVV (MOVVconst [c]) (MOVVconst [d]))) && d != 0 => (MOVVconst [c/d]) +(Select1 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) && d != 0 => (MOVVconst [int64(uint64(c)/uint64(d))]) +(Select0 (DIVV (MOVVconst [c]) (MOVVconst [d]))) && d != 0 => (MOVVconst [c%d]) // mod +(Select0 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) && d != 0 => (MOVVconst [int64(uint64(c)%uint64(d))]) // mod (ANDconst [c] (MOVVconst [d])) => (MOVVconst [c&d]) (ANDconst [c] (ANDconst [d] x)) => (ANDconst [c&d] x) (ORconst [c] (MOVVconst [d])) => (MOVVconst [c|d]) diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go index 68495c558c..d9d439fa63 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM.go +++ b/src/cmd/compile/internal/ssa/rewriteARM.go @@ -15599,6 +15599,7 @@ func rewriteValueARM_OpSelect0(v *Value) bool { return true } // match: (Select0 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) + // cond: d != 0 // result: (MOVWconst [int32(uint32(c)/uint32(d))]) for { if v_0.Op != OpARMCALLudiv { @@ -15615,6 +15616,9 @@ func rewriteValueARM_OpSelect0(v *Value) bool { break } d := auxIntToInt32(v_0_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpARMMOVWconst) v.AuxInt = int32ToAuxInt(int32(uint32(c) / uint32(d))) return true @@ -15661,6 +15665,7 @@ func rewriteValueARM_OpSelect1(v *Value) bool { return true } // match: (Select1 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) + // cond: d != 0 // result: (MOVWconst [int32(uint32(c)%uint32(d))]) for { if v_0.Op != OpARMCALLudiv { @@ -15677,6 +15682,9 @@ func rewriteValueARM_OpSelect1(v *Value) bool { break } d := auxIntToInt32(v_0_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpARMMOVWconst) v.AuxInt = int32ToAuxInt(int32(uint32(c) % uint32(d))) return true diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index 353696bf39..5d5e526add 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -3396,6 +3396,7 @@ func rewriteValueARM64_OpARM64DIV(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (DIV (MOVDconst [c]) (MOVDconst [d])) + // cond: d != 0 // result: (MOVDconst [c/d]) for { if v_0.Op != OpARM64MOVDconst { @@ -3406,6 +3407,9 @@ func rewriteValueARM64_OpARM64DIV(v *Value) bool { break } d := auxIntToInt64(v_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpARM64MOVDconst) v.AuxInt = int64ToAuxInt(c / d) return true @@ -3416,6 +3420,7 @@ func rewriteValueARM64_OpARM64DIVW(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (DIVW (MOVDconst [c]) (MOVDconst [d])) + // cond: d != 0 // result: (MOVDconst [int64(int32(c)/int32(d))]) for { if v_0.Op != OpARM64MOVDconst { @@ -3426,6 +3431,9 @@ func rewriteValueARM64_OpARM64DIVW(v *Value) bool { break } d := auxIntToInt64(v_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpARM64MOVDconst) v.AuxInt = int64ToAuxInt(int64(int32(c) / int32(d))) return true @@ -6165,6 +6173,7 @@ func rewriteValueARM64_OpARM64MOD(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (MOD (MOVDconst [c]) (MOVDconst [d])) + // cond: d != 0 // result: (MOVDconst [c%d]) for { if v_0.Op != OpARM64MOVDconst { @@ -6175,6 +6184,9 @@ func rewriteValueARM64_OpARM64MOD(v *Value) bool { break } d := auxIntToInt64(v_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpARM64MOVDconst) v.AuxInt = int64ToAuxInt(c % d) return true @@ -6185,6 +6197,7 @@ func rewriteValueARM64_OpARM64MODW(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (MODW (MOVDconst [c]) (MOVDconst [d])) + // cond: d != 0 // result: (MOVDconst [int64(int32(c)%int32(d))]) for { if v_0.Op != OpARM64MOVDconst { @@ -6195,6 +6208,9 @@ func rewriteValueARM64_OpARM64MODW(v *Value) bool { break } d := auxIntToInt64(v_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpARM64MOVDconst) v.AuxInt = int64ToAuxInt(int64(int32(c) % int32(d))) return true @@ -20423,6 +20439,7 @@ func rewriteValueARM64_OpARM64UDIV(v *Value) bool { return true } // match: (UDIV (MOVDconst [c]) (MOVDconst [d])) + // cond: d != 0 // result: (MOVDconst [int64(uint64(c)/uint64(d))]) for { if v_0.Op != OpARM64MOVDconst { @@ -20433,6 +20450,9 @@ func rewriteValueARM64_OpARM64UDIV(v *Value) bool { break } d := auxIntToInt64(v_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpARM64MOVDconst) v.AuxInt = int64ToAuxInt(int64(uint64(c) / uint64(d))) return true @@ -20475,6 +20495,7 @@ func rewriteValueARM64_OpARM64UDIVW(v *Value) bool { return true } // match: (UDIVW (MOVDconst [c]) (MOVDconst [d])) + // cond: d != 0 // result: (MOVDconst [int64(uint32(c)/uint32(d))]) for { if v_0.Op != OpARM64MOVDconst { @@ -20485,6 +20506,9 @@ func rewriteValueARM64_OpARM64UDIVW(v *Value) bool { break } d := auxIntToInt64(v_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpARM64MOVDconst) v.AuxInt = int64ToAuxInt(int64(uint32(c) / uint32(d))) return true @@ -20539,6 +20563,7 @@ func rewriteValueARM64_OpARM64UMOD(v *Value) bool { return true } // match: (UMOD (MOVDconst [c]) (MOVDconst [d])) + // cond: d != 0 // result: (MOVDconst [int64(uint64(c)%uint64(d))]) for { if v_0.Op != OpARM64MOVDconst { @@ -20549,6 +20574,9 @@ func rewriteValueARM64_OpARM64UMOD(v *Value) bool { break } d := auxIntToInt64(v_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpARM64MOVDconst) v.AuxInt = int64ToAuxInt(int64(uint64(c) % uint64(d))) return true @@ -20608,6 +20636,7 @@ func rewriteValueARM64_OpARM64UMODW(v *Value) bool { return true } // match: (UMODW (MOVDconst [c]) (MOVDconst [d])) + // cond: d != 0 // result: (MOVDconst [int64(uint32(c)%uint32(d))]) for { if v_0.Op != OpARM64MOVDconst { @@ -20618,6 +20647,9 @@ func rewriteValueARM64_OpARM64UMODW(v *Value) bool { break } d := auxIntToInt64(v_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpARM64MOVDconst) v.AuxInt = int64ToAuxInt(int64(uint32(c) % uint32(d))) return true diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS.go b/src/cmd/compile/internal/ssa/rewriteMIPS.go index bbc331014f..3fc5527955 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS.go @@ -6421,6 +6421,7 @@ func rewriteValueMIPS_OpSelect0(v *Value) bool { break } // match: (Select0 (DIV (MOVWconst [c]) (MOVWconst [d]))) + // cond: d != 0 // result: (MOVWconst [c%d]) for { if v_0.Op != OpMIPSDIV { @@ -6437,11 +6438,15 @@ func rewriteValueMIPS_OpSelect0(v *Value) bool { break } d := auxIntToInt32(v_0_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpMIPSMOVWconst) v.AuxInt = int32ToAuxInt(c % d) return true } // match: (Select0 (DIVU (MOVWconst [c]) (MOVWconst [d]))) + // cond: d != 0 // result: (MOVWconst [int32(uint32(c)%uint32(d))]) for { if v_0.Op != OpMIPSDIVU { @@ -6458,6 +6463,9 @@ func rewriteValueMIPS_OpSelect0(v *Value) bool { break } d := auxIntToInt32(v_0_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpMIPSMOVWconst) v.AuxInt = int32ToAuxInt(int32(uint32(c) % uint32(d))) return true @@ -6609,6 +6617,7 @@ func rewriteValueMIPS_OpSelect1(v *Value) bool { break } // match: (Select1 (DIV (MOVWconst [c]) (MOVWconst [d]))) + // cond: d != 0 // result: (MOVWconst [c/d]) for { if v_0.Op != OpMIPSDIV { @@ -6625,11 +6634,15 @@ func rewriteValueMIPS_OpSelect1(v *Value) bool { break } d := auxIntToInt32(v_0_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpMIPSMOVWconst) v.AuxInt = int32ToAuxInt(c / d) return true } // match: (Select1 (DIVU (MOVWconst [c]) (MOVWconst [d]))) + // cond: d != 0 // result: (MOVWconst [int32(uint32(c)/uint32(d))]) for { if v_0.Op != OpMIPSDIVU { @@ -6646,6 +6659,9 @@ func rewriteValueMIPS_OpSelect1(v *Value) bool { break } d := auxIntToInt32(v_0_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpMIPSMOVWconst) v.AuxInt = int32ToAuxInt(int32(uint32(c) / uint32(d))) return true diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go index 29e3a8a363..d78f6089af 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go @@ -6887,6 +6887,7 @@ func rewriteValueMIPS64_OpSelect0(v *Value) bool { return true } // match: (Select0 (DIVV (MOVVconst [c]) (MOVVconst [d]))) + // cond: d != 0 // result: (MOVVconst [c%d]) for { if v_0.Op != OpMIPS64DIVV { @@ -6903,11 +6904,15 @@ func rewriteValueMIPS64_OpSelect0(v *Value) bool { break } d := auxIntToInt64(v_0_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpMIPS64MOVVconst) v.AuxInt = int64ToAuxInt(c % d) return true } // match: (Select0 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) + // cond: d != 0 // result: (MOVVconst [int64(uint64(c)%uint64(d))]) for { if v_0.Op != OpMIPS64DIVVU { @@ -6924,6 +6929,9 @@ func rewriteValueMIPS64_OpSelect0(v *Value) bool { break } d := auxIntToInt64(v_0_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpMIPS64MOVVconst) v.AuxInt = int64ToAuxInt(int64(uint64(c) % uint64(d))) return true @@ -7099,6 +7107,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value) bool { break } // match: (Select1 (DIVV (MOVVconst [c]) (MOVVconst [d]))) + // cond: d != 0 // result: (MOVVconst [c/d]) for { if v_0.Op != OpMIPS64DIVV { @@ -7115,11 +7124,15 @@ func rewriteValueMIPS64_OpSelect1(v *Value) bool { break } d := auxIntToInt64(v_0_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpMIPS64MOVVconst) v.AuxInt = int64ToAuxInt(c / d) return true } // match: (Select1 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) + // cond: d != 0 // result: (MOVVconst [int64(uint64(c)/uint64(d))]) for { if v_0.Op != OpMIPS64DIVVU { @@ -7136,6 +7149,9 @@ func rewriteValueMIPS64_OpSelect1(v *Value) bool { break } d := auxIntToInt64(v_0_1.AuxInt) + if !(d != 0) { + break + } v.reset(OpMIPS64MOVVconst) v.AuxInt = int64ToAuxInt(int64(uint64(c) / uint64(d))) return true diff --git a/test/fixedbugs/issue43099.go b/test/fixedbugs/issue43099.go new file mode 100644 index 0000000000..16f18e5f96 --- /dev/null +++ b/test/fixedbugs/issue43099.go @@ -0,0 +1,34 @@ +// compile + +// Copyright 2020 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. + +// Check to make sure we don't try to constant fold a divide by zero. +// This is a tricky test, as we need a value that's not recognized as 0 +// until lowering (otherwise it gets handled in a different path). + +package p + +func f() { + var i int + var s string + for i > 0 { + _ = s[0] + i++ + } + + var c chan int + c <- 1 % i +} + +func f32() uint32 { + s := "\x00\x00\x00\x00" + c := uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 | uint32(s[3])<<24 + return 1 / c +} +func f64() uint64 { + s := "\x00\x00\x00\x00\x00\x00\x00\x00" + c := uint64(s[0]) | uint64(s[1])<<8 | uint64(s[2])<<16 | uint64(s[3])<<24 | uint64(s[4])<<32 | uint64(s[5])<<40 | uint64(s[6])<<48 | uint64(s[7])<<56 + return 1 / c +} -- cgit v1.3 From 6d2b3351f6312ebc924d0014013088c69b9c1bc2 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 9 Dec 2020 18:51:12 -0800 Subject: test: match gofrontend error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixedbugs/bug13343.go:10:12: error: initialization expressions for ‘b’ and ‘c’ depend upon each other fixedbugs/bug13343.go:11:9: note: ‘c’ defined here fixedbugs/bug13343.go:11:9: error: initialization expression for ‘c’ depends upon itself fixedbugs/bug13343.go:11:9: error: initialization expressions for ‘c’ and ‘b’ depend upon each other fixedbugs/bug13343.go:10:12: note: ‘b’ defined here fixedbugs/issue10700.dir/test.go:24:10: error: reference to method ‘Do’ in type that is pointer to interface, not interface fixedbugs/issue10700.dir/test.go:25:10: error: reference to method ‘do’ in type that is pointer to interface, not interface fixedbugs/issue10700.dir/test.go:27:10: error: reference to method ‘Dont’ in type that is pointer to interface, not interface fixedbugs/issue10700.dir/test.go:28:13: error: reference to undefined field or method ‘Dont’ fixedbugs/issue10700.dir/test.go:31:10: error: reference to undefined field or method ‘do’ fixedbugs/issue10700.dir/test.go:33:13: error: reference to undefined field or method ‘do’ fixedbugs/issue10700.dir/test.go:34:10: error: reference to undefined field or method ‘Dont’ fixedbugs/issue10700.dir/test.go:35:13: error: reference to undefined field or method ‘Dont’ fixedbugs/issue10700.dir/test.go:37:10: error: reference to method ‘Do’ in type that is pointer to interface, not interface fixedbugs/issue10700.dir/test.go:38:10: error: reference to method ‘do’ in type that is pointer to interface, not interface fixedbugs/issue10700.dir/test.go:40:13: error: reference to undefined field or method ‘do’ fixedbugs/issue10700.dir/test.go:41:10: error: reference to method ‘Dont’ in type that is pointer to interface, not interface fixedbugs/issue10700.dir/test.go:42:13: error: reference to undefined field or method ‘Dont’ fixedbugs/issue10700.dir/test.go:43:10: error: reference to method ‘secret’ in type that is pointer to interface, not interface fixedbugs/issue10700.dir/test.go:44:13: error: reference to unexported field or method ‘secret’ fixedbugs/issue10975.go:13:9: error: interface contains embedded non-interface fixedbugs/issue11326.go:26:17: error: floating-point constant overflow fixedbugs/issue11326.go:27:17: error: floating-point constant overflow fixedbugs/issue11326.go:28:17: error: floating-point constant overflow fixedbugs/issue11361.go:9:11: error: import file ‘fmt’ not found fixedbugs/issue11361.go:11:11: error: reference to undefined name ‘fmt’ fixedbugs/issue11371.go:12:15: error: floating-point constant truncated to integer fixedbugs/issue11371.go:13:15: error: integer constant overflow fixedbugs/issue11371.go:17:15: error: floating-point constant truncated to integer fixedbugs/issue11590.go:9:17: error: integer constant overflow fixedbugs/issue11590.go:9:17: error: integer constant overflow fixedbugs/issue11590.go:10:22: error: complex real part overflow fixedbugs/issue11590.go:10:22: error: complex real part overflow fixedbugs/issue11590.go:11:23: error: complex real part overflow fixedbugs/issue11590.go:11:23: error: complex real part overflow fixedbugs/issue11590.go:9:19: error: integer constant overflow fixedbugs/issue11590.go:10:24: error: complex real part overflow fixedbugs/issue11590.go:11:25: error: complex real part overflow fixedbugs/issue11610.go:11:7: error: import path is empty fixedbugs/issue11610.go:12:4: error: invalid character 0x3f in input file fixedbugs/issue11610.go:14:1: error: expected identifier fixedbugs/issue11610.go:14:1: error: expected type fixedbugs/issue11614.go:14:9: error: interface contains embedded non-interface fixedbugs/issue13248.go:13:1: error: expected operand fixedbugs/issue13248.go:13:1: error: missing ‘)’ fixedbugs/issue13248.go:12:5: error: reference to undefined name ‘foo’ fixedbugs/issue13266.go:10:8: error: package name must be an identifier fixedbugs/issue13266.go:10:8: error: expected ‘;’ or newline after package clause fixedbugs/issue13266.go:10:8: error: expected declaration fixedbugs/issue13273.go:50:18: error: expected ‘chan’ fixedbugs/issue13273.go:53:24: error: expected ‘chan’ fixedbugs/issue13274.go:11:58: error: expected ‘}’ fixedbugs/issue13365.go:14:19: error: index expression is negative fixedbugs/issue13365.go:15:21: error: index expression is negative fixedbugs/issue13365.go:16:22: error: index expression is negative fixedbugs/issue13365.go:19:13: error: some element keys in composite literal are out of range fixedbugs/issue13365.go:22:19: error: incompatible type for element 1 in composite literal fixedbugs/issue13365.go:23:21: error: incompatible type for element 1 in composite literal fixedbugs/issue13365.go:24:22: error: incompatible type for element 1 in composite literal fixedbugs/issue13415.go:14:5: error: redefinition of ‘x’ fixedbugs/issue13415.go:14:5: note: previous definition of ‘x’ was here fixedbugs/issue13415.go:14:5: error: ‘x’ declared but not used fixedbugs/issue13471.go:12:25: error: floating-point constant truncated to integer fixedbugs/issue13471.go:13:25: error: floating-point constant truncated to integer fixedbugs/issue13471.go:14:25: error: floating-point constant truncated to integer fixedbugs/issue13471.go:15:24: error: floating-point constant truncated to integer fixedbugs/issue13471.go:16:23: error: floating-point constant truncated to integer fixedbugs/issue13471.go:18:26: error: floating-point constant truncated to integer fixedbugs/issue13471.go:19:26: error: floating-point constant truncated to integer fixedbugs/issue13471.go:20:26: error: floating-point constant truncated to integer fixedbugs/issue13471.go:21:25: error: floating-point constant truncated to integer fixedbugs/issue13471.go:22:24: error: floating-point constant truncated to integer fixedbugs/issue13471.go:24:24: error: floating-point constant truncated to integer fixedbugs/issue13821b.go:18:12: error: incompatible types in binary expression fixedbugs/issue13821b.go:19:13: error: incompatible types in binary expression fixedbugs/issue13821b.go:20:13: error: incompatible types in binary expression fixedbugs/issue13821b.go:21:13: error: incompatible types in binary expression fixedbugs/issue13821b.go:22:13: error: incompatible types in binary expression fixedbugs/issue13821b.go:24:12: error: incompatible types in binary expression fixedbugs/issue14006.go:24:18: error: expected ‘;’ or ‘}’ or newline fixedbugs/issue14006.go:30:18: error: expected ‘;’ or ‘}’ or newline fixedbugs/issue14006.go:37:22: error: expected ‘;’ or ‘}’ or newline fixedbugs/issue14006.go:43:22: error: expected ‘;’ or ‘}’ or newline fixedbugs/issue14006.go:59:17: note: previous definition of ‘labelname’ was here fixedbugs/issue14006.go:64:17: error: label ‘labelname’ already defined fixedbugs/issue14006.go:24:17: error: value computed is not used fixedbugs/issue14006.go:30:17: error: value computed is not used fixedbugs/issue14006.go:37:20: error: value computed is not used fixedbugs/issue14006.go:43:20: error: value computed is not used fixedbugs/issue14006.go:59:17: error: label ‘labelname’ defined and not used fixedbugs/issue14010.go:13:14: error: invalid left hand side of assignment fixedbugs/issue14010.go:14:14: error: invalid left hand side of assignment fixedbugs/issue14010.go:14:9: error: invalid use of type fixedbugs/issue14321.go:30:10: error: method ‘F’ is ambiguous in type ‘C’ fixedbugs/issue14321.go:31:10: error: ‘G’ is ambiguous via ‘A’ and ‘B’ fixedbugs/issue14321.go:33:10: error: type ‘C’ has no method ‘I’ fixedbugs/issue8183.go:12:14: error: integer constant overflow fixedbugs/issue9036.go:21:12: error: invalid prefix for floating constant fixedbugs/issue9036.go:22:12: error: invalid prefix for floating constant fixedbugs/issue9076.go:14:5: error: incompatible type in initialization (cannot use type uintptr as type int32) fixedbugs/issue9076.go:15:5: error: incompatible type in initialization (cannot use type uintptr as type int32) For issue9083.go avoid an error about a variable that is set but not used. fixedbugs/issue9370.go:105:13: error: cannot use ‘_’ as value fixedbugs/issue9370.go:106:13: error: cannot use ‘_’ as value fixedbugs/issue9370.go:107:13: error: cannot use ‘_’ as value fixedbugs/issue9370.go:108:13: error: cannot use ‘_’ as value fixedbugs/issue9370.go:109:13: error: cannot use ‘_’ as value fixedbugs/issue9370.go:110:13: error: cannot use ‘_’ as value fixedbugs/issue9370.go:112:18: error: cannot use ‘_’ as value fixedbugs/issue9370.go:113:18: error: cannot use ‘_’ as value fixedbugs/issue9370.go:114:18: error: cannot use ‘_’ as value fixedbugs/issue9370.go:115:18: error: cannot use ‘_’ as value fixedbugs/issue9370.go:116:18: error: cannot use ‘_’ as value fixedbugs/issue9370.go:117:18: error: cannot use ‘_’ as value fixedbugs/issue9370.go:119:13: error: cannot use ‘_’ as value fixedbugs/issue9370.go:119:18: error: cannot use ‘_’ as value fixedbugs/issue9370.go:36:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:39:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:43:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:46:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:50:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:53:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:56:15: error: incompatible types in binary expression fixedbugs/issue9370.go:57:15: error: incompatible types in binary expression fixedbugs/issue9370.go:58:15: error: incompatible types in binary expression fixedbugs/issue9370.go:59:15: error: incompatible types in binary expression fixedbugs/issue9370.go:60:15: error: incompatible types in binary expression fixedbugs/issue9370.go:61:15: error: incompatible types in binary expression fixedbugs/issue9370.go:65:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:68:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:70:15: error: incompatible types in binary expression fixedbugs/issue9370.go:71:15: error: incompatible types in binary expression fixedbugs/issue9370.go:72:15: error: incompatible types in binary expression fixedbugs/issue9370.go:73:15: error: incompatible types in binary expression fixedbugs/issue9370.go:74:15: error: incompatible types in binary expression fixedbugs/issue9370.go:75:15: error: incompatible types in binary expression fixedbugs/issue9370.go:77:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:78:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:79:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:80:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:81:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:82:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:84:15: error: incompatible types in binary expression fixedbugs/issue9370.go:85:15: error: incompatible types in binary expression fixedbugs/issue9370.go:86:15: error: incompatible types in binary expression fixedbugs/issue9370.go:87:15: error: incompatible types in binary expression fixedbugs/issue9370.go:88:15: error: incompatible types in binary expression fixedbugs/issue9370.go:89:15: error: incompatible types in binary expression fixedbugs/issue9370.go:91:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:92:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:93:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:94:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:95:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:96:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:98:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:99:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:100:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:101:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:102:15: error: invalid operation (func can only be compared to nil) fixedbugs/issue9370.go:103:15: error: invalid comparison of non-ordered type fixedbugs/issue9370.go:121:15: error: incompatible types in binary expression fixedbugs/issue9370.go:122:15: error: incompatible types in binary expression fixedbugs/issue9370.go:123:15: error: incompatible types in binary expression fixedbugs/issue9370.go:124:15: error: incompatible types in binary expression Change-Id: I4089de4919112b08f5f2bbec20f84fcc7dbe3955 Reviewed-on: https://go-review.googlesource.com/c/go/+/276832 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Than McIntosh --- test/fixedbugs/bug13343.go | 4 +- test/fixedbugs/issue10700.dir/test.go | 30 ++++---- test/fixedbugs/issue10975.go | 2 +- test/fixedbugs/issue11326.go | 16 ++-- test/fixedbugs/issue11361.go | 4 +- test/fixedbugs/issue11371.go | 6 +- test/fixedbugs/issue11590.go | 6 +- test/fixedbugs/issue11610.go | 4 +- test/fixedbugs/issue11614.go | 2 +- test/fixedbugs/issue13248.go | 4 +- test/fixedbugs/issue13266.go | 2 +- test/fixedbugs/issue13273.go | 4 +- test/fixedbugs/issue13274.go | 2 +- test/fixedbugs/issue13365.go | 14 ++-- test/fixedbugs/issue13415.go | 2 +- test/fixedbugs/issue13471.go | 22 +++--- test/fixedbugs/issue13821b.go | 12 +-- test/fixedbugs/issue14006.go | 14 ++-- test/fixedbugs/issue14010.go | 4 +- test/fixedbugs/issue14321.go | 8 +- test/fixedbugs/issue8183.go | 6 +- test/fixedbugs/issue9036.go | 4 +- test/fixedbugs/issue9076.go | 4 +- test/fixedbugs/issue9083.go | 1 + test/fixedbugs/issue9370.go | 140 +++++++++++++++++----------------- 25 files changed, 159 insertions(+), 158 deletions(-) (limited to 'test/fixedbugs') diff --git a/test/fixedbugs/bug13343.go b/test/fixedbugs/bug13343.go index 5dc736d443..a7febeae7e 100644 --- a/test/fixedbugs/bug13343.go +++ b/test/fixedbugs/bug13343.go @@ -7,8 +7,8 @@ package main var ( - a, b = f() // ERROR "initialization loop|depends upon itself" - c = b + a, b = f() // ERROR "initialization loop|depends upon itself|depend upon each other" + c = b // GCCGO_ERROR "depends upon itself|depend upon each other" ) func f() (int, int) { diff --git a/test/fixedbugs/issue10700.dir/test.go b/test/fixedbugs/issue10700.dir/test.go index 2033efc9d8..2dfc24af07 100644 --- a/test/fixedbugs/issue10700.dir/test.go +++ b/test/fixedbugs/issue10700.dir/test.go @@ -21,27 +21,27 @@ func (me *HasAMethod) Do() { } func InMyCode(x *Imported, y *HasAMethod, z *other.Exported) { - x.Do() // ERROR "x\.Do undefined \(type \*Imported is pointer to interface, not interface\)" - x.do() // ERROR "x\.do undefined \(type \*Imported is pointer to interface, not interface\)" + x.Do() // ERROR "x\.Do undefined \(type \*Imported is pointer to interface, not interface\)|type that is pointer to interface" + x.do() // ERROR "x\.do undefined \(type \*Imported is pointer to interface, not interface\)|type that is pointer to interface" (*x).Do() - x.Dont() // ERROR "x\.Dont undefined \(type \*Imported is pointer to interface, not interface\)" - (*x).Dont() // ERROR "\(\*x\)\.Dont undefined \(type Imported has no field or method Dont\)" + x.Dont() // ERROR "x\.Dont undefined \(type \*Imported is pointer to interface, not interface\)|type that is pointer to interface" + (*x).Dont() // ERROR "\(\*x\)\.Dont undefined \(type Imported has no field or method Dont\)|reference to undefined field or method" y.Do() - y.do() // ERROR "y\.do undefined \(type \*HasAMethod has no field or method do, but does have Do\)" + y.do() // ERROR "y\.do undefined \(type \*HasAMethod has no field or method do, but does have Do\)|reference to undefined field or method" (*y).Do() - (*y).do() // ERROR "\(\*y\)\.do undefined \(type HasAMethod has no field or method do, but does have Do\)" - y.Dont() // ERROR "y\.Dont undefined \(type \*HasAMethod has no field or method Dont\)" - (*y).Dont() // ERROR "\(\*y\)\.Dont undefined \(type HasAMethod has no field or method Dont\)" + (*y).do() // ERROR "\(\*y\)\.do undefined \(type HasAMethod has no field or method do, but does have Do\)|reference to undefined field or method" + y.Dont() // ERROR "y\.Dont undefined \(type \*HasAMethod has no field or method Dont\)|reference to undefined field or method" + (*y).Dont() // ERROR "\(\*y\)\.Dont undefined \(type HasAMethod has no field or method Dont\)|reference to undefined field or method" - z.Do() // ERROR "z\.Do undefined \(type \*other\.Exported is pointer to interface, not interface\)" - z.do() // ERROR "z\.do undefined \(type \*other\.Exported is pointer to interface, not interface\)" + z.Do() // ERROR "z\.Do undefined \(type \*other\.Exported is pointer to interface, not interface\)|type that is pointer to interface" + z.do() // ERROR "z\.do undefined \(type \*other\.Exported is pointer to interface, not interface\)|type that is pointer to interface" (*z).Do() - (*z).do() // ERROR "\(\*z\)\.do undefined \(type other.Exported has no field or method do, but does have Do\)" - z.Dont() // ERROR "z\.Dont undefined \(type \*other\.Exported is pointer to interface, not interface\)" - (*z).Dont() // ERROR "\(\*z\)\.Dont undefined \(type other\.Exported has no field or method Dont\)" - z.secret() // ERROR "z\.secret undefined \(type \*other\.Exported is pointer to interface, not interface\)" - (*z).secret() // ERROR "\(\*z\)\.secret undefined \(cannot refer to unexported field or method secret\)" + (*z).do() // ERROR "\(\*z\)\.do undefined \(type other.Exported has no field or method do, but does have Do\)|reference to undefined field or method" + z.Dont() // ERROR "z\.Dont undefined \(type \*other\.Exported is pointer to interface, not interface\)|type that is pointer to interface" + (*z).Dont() // ERROR "\(\*z\)\.Dont undefined \(type other\.Exported has no field or method Dont\)|reference to undefined field or method" + z.secret() // ERROR "z\.secret undefined \(type \*other\.Exported is pointer to interface, not interface\)|type that is pointer to interface" + (*z).secret() // ERROR "\(\*z\)\.secret undefined \(cannot refer to unexported field or method secret\)|reference to unexported field or method" } diff --git a/test/fixedbugs/issue10975.go b/test/fixedbugs/issue10975.go index b5f043f0a7..933badfd2f 100644 --- a/test/fixedbugs/issue10975.go +++ b/test/fixedbugs/issue10975.go @@ -10,7 +10,7 @@ package main type I interface { - int // ERROR "interface contains embedded non-interface int" + int // ERROR "interface contains embedded non-interface" } func New() I { diff --git a/test/fixedbugs/issue11326.go b/test/fixedbugs/issue11326.go index 82754c73fb..f3037d53c4 100644 --- a/test/fixedbugs/issue11326.go +++ b/test/fixedbugs/issue11326.go @@ -18,14 +18,14 @@ func main() { // Any implementation must be able to handle these constants at // compile time (even though they cannot be assigned to a float64). - var _ = 1e646456992 // ERROR "1e\+646456992 overflows float64" - var _ = 1e64645699 // ERROR "1e\+64645699 overflows float64" - var _ = 1e6464569 // ERROR "1e\+6464569 overflows float64" - var _ = 1e646456 // ERROR "1e\+646456 overflows float64" - var _ = 1e64645 // ERROR "1e\+64645 overflows float64" - var _ = 1e6464 // ERROR "1e\+6464 overflows float64" - var _ = 1e646 // ERROR "1e\+646 overflows float64" - var _ = 1e309 // ERROR "1e\+309 overflows float64" + var _ = 1e646456992 // ERROR "1e\+646456992 overflows float64|floating-point constant overflow" + var _ = 1e64645699 // ERROR "1e\+64645699 overflows float64|floating-point constant overflow" + var _ = 1e6464569 // ERROR "1e\+6464569 overflows float64|floating-point constant overflow" + var _ = 1e646456 // ERROR "1e\+646456 overflows float64|floating-point constant overflow" + var _ = 1e64645 // ERROR "1e\+64645 overflows float64|floating-point constant overflow" + var _ = 1e6464 // ERROR "1e\+6464 overflows float64|floating-point constant overflow" + var _ = 1e646 // ERROR "1e\+646 overflows float64|floating-point constant overflow" + var _ = 1e309 // ERROR "1e\+309 overflows float64|floating-point constant overflow" var _ = 1e308 } diff --git a/test/fixedbugs/issue11361.go b/test/fixedbugs/issue11361.go index 1260ea89c9..63dbf05d73 100644 --- a/test/fixedbugs/issue11361.go +++ b/test/fixedbugs/issue11361.go @@ -6,6 +6,6 @@ package a -import "fmt" // ERROR "imported and not used" +import "fmt" // GC_ERROR "imported and not used" -const n = fmt // ERROR "fmt without selector" +const n = fmt // ERROR "fmt without selector|unexpected reference to package" diff --git a/test/fixedbugs/issue11371.go b/test/fixedbugs/issue11371.go index b2d966fac8..05b8fcfebe 100644 --- a/test/fixedbugs/issue11371.go +++ b/test/fixedbugs/issue11371.go @@ -9,9 +9,9 @@ package issue11371 -const a int = 1.1 // ERROR "constant 1.1 truncated to integer" -const b int = 1e20 // ERROR "overflows int" +const a int = 1.1 // ERROR "constant 1.1 truncated to integer|floating-point constant truncated to integer" +const b int = 1e20 // ERROR "overflows int|integer constant overflow" const c int = 1 + 1e-100 // ERROR "constant truncated to integer" const d int = 1 - 1e-100 // ERROR "constant truncated to integer" const e int = 1.00000001 // ERROR "constant truncated to integer" -const f int = 0.00000001 // ERROR "constant 1e-08 truncated to integer" +const f int = 0.00000001 // ERROR "constant 1e-08 truncated to integer|floating-point constant truncated to integer" diff --git a/test/fixedbugs/issue11590.go b/test/fixedbugs/issue11590.go index 09345473fb..f2a955f96d 100644 --- a/test/fixedbugs/issue11590.go +++ b/test/fixedbugs/issue11590.go @@ -6,6 +6,6 @@ package p -var _ = int8(4) * 300 // ERROR "constant 300 overflows int8" "constant 1200 overflows int8" -var _ = complex64(1) * 1e200 // ERROR "constant 1e\+200 overflows complex64" -var _ = complex128(1) * 1e500 // ERROR "constant 1e\+500 overflows complex128" +var _ = int8(4) * 300 // ERROR "constant 300 overflows int8" "constant 1200 overflows int8|integer constant overflow" +var _ = complex64(1) * 1e200 // ERROR "constant 1e\+200 overflows complex64|complex real part overflow" +var _ = complex128(1) * 1e500 // ERROR "constant 1e\+500 overflows complex128|complex real part overflow" diff --git a/test/fixedbugs/issue11610.go b/test/fixedbugs/issue11610.go index 8ca31bf394..7ebfae6709 100644 --- a/test/fixedbugs/issue11610.go +++ b/test/fixedbugs/issue11610.go @@ -9,9 +9,9 @@ package a import"" // ERROR "import path is empty" -var? // ERROR "invalid character U\+003F '\?'" +var? // ERROR "invalid character U\+003F '\?'|invalid character 0x3f in input file" -var x int // ERROR "unexpected var" +var x int // ERROR "unexpected var|expected identifier|expected type" func main() { } diff --git a/test/fixedbugs/issue11614.go b/test/fixedbugs/issue11614.go index 91f134d44a..d1642a3faf 100644 --- a/test/fixedbugs/issue11614.go +++ b/test/fixedbugs/issue11614.go @@ -11,7 +11,7 @@ package main type I interface { - int // ERROR "interface contains embedded non-interface int" + int // ERROR "interface contains embedded non-interface" } func n() { diff --git a/test/fixedbugs/issue13248.go b/test/fixedbugs/issue13248.go index 524628159c..e23ba47b58 100644 --- a/test/fixedbugs/issue13248.go +++ b/test/fixedbugs/issue13248.go @@ -9,5 +9,5 @@ package main func main() { - foo( -} // ERROR "unexpected }" + foo( // GCCGO_ERROR "undefined name" +} // ERROR "unexpected }|expected operand|missing" diff --git a/test/fixedbugs/issue13266.go b/test/fixedbugs/issue13266.go index 37c5594a24..73c9e16bcc 100644 --- a/test/fixedbugs/issue13266.go +++ b/test/fixedbugs/issue13266.go @@ -7,4 +7,4 @@ // Offending character % must not be interpreted as // start of format verb when emitting error message. -package% // ERROR "unexpected %" +package% // ERROR "unexpected %|package name must be an identifier|after package clause|expected declaration" diff --git a/test/fixedbugs/issue13273.go b/test/fixedbugs/issue13273.go index f8f679daab..2498da4d47 100644 --- a/test/fixedbugs/issue13273.go +++ b/test/fixedbugs/issue13273.go @@ -47,9 +47,9 @@ func f() { <-(<-chan (<-chan (<-chan (<-chan int))))(nil) <-(<-chan (<-chan (<-chan (<-chan (<-chan int)))))(nil) - type _ <-<-chan int // ERROR "unexpected <-, expecting chan" + type _ <-<-chan int // ERROR "unexpected <-, expecting chan|expected .*chan.*" <-<-chan int // ERROR "unexpected <-, expecting chan|expecting {" (new parser: same error as for type decl) - type _ <-chan<-int // ERROR "unexpected int, expecting chan|expecting chan" + type _ <-chan<-int // ERROR "unexpected int, expecting chan|expected .*chan.*|expecting chan|expected .*;.* or .*}.* or newline" <-chan<-int // ERROR "unexpected int, expecting chan|expecting {" (new parser: same error as for type decl) } diff --git a/test/fixedbugs/issue13274.go b/test/fixedbugs/issue13274.go index 480f5bcc11..816bd9b8f2 100644 --- a/test/fixedbugs/issue13274.go +++ b/test/fixedbugs/issue13274.go @@ -8,4 +8,4 @@ package p -var f = func() { // ERROR "unexpected EOF" \ No newline at end of file +var f = func() { // ERROR "unexpected EOF|expected .*}.*" \ No newline at end of file diff --git a/test/fixedbugs/issue13365.go b/test/fixedbugs/issue13365.go index 4bd103e38d..31a663eb1f 100644 --- a/test/fixedbugs/issue13365.go +++ b/test/fixedbugs/issue13365.go @@ -11,15 +11,15 @@ package main var t struct{} func main() { - _ = []int{-1: 0} // ERROR "index must be non\-negative integer constant" - _ = [10]int{-1: 0} // ERROR "index must be non\-negative integer constant" - _ = [...]int{-1: 0} // ERROR "index must be non\-negative integer constant" + _ = []int{-1: 0} // ERROR "index must be non\-negative integer constant|index expression is negative" + _ = [10]int{-1: 0} // ERROR "index must be non\-negative integer constant|index expression is negative" + _ = [...]int{-1: 0} // ERROR "index must be non\-negative integer constant|index expression is negative" _ = []int{100: 0} - _ = [10]int{100: 0} // ERROR "array index 100 out of bounds" + _ = [10]int{100: 0} // ERROR "array index 100 out of bounds|out of range" _ = [...]int{100: 0} - _ = []int{t} // ERROR "cannot use .* as type int in slice literal" - _ = [10]int{t} // ERROR "cannot use .* as type int in array literal" - _ = [...]int{t} // ERROR "cannot use .* as type int in array literal" + _ = []int{t} // ERROR "cannot use .* as type int in slice literal|incompatible type" + _ = [10]int{t} // ERROR "cannot use .* as type int in array literal|incompatible type" + _ = [...]int{t} // ERROR "cannot use .* as type int in array literal|incompatible type" } diff --git a/test/fixedbugs/issue13415.go b/test/fixedbugs/issue13415.go index 989a1ed50f..4c4655e547 100644 --- a/test/fixedbugs/issue13415.go +++ b/test/fixedbugs/issue13415.go @@ -11,7 +11,7 @@ package p func f() { select { - case x, x := <-func() chan int { // ERROR "x repeated on left side of :=" + case x, x := <-func() chan int { // ERROR "x repeated on left side of :=|redefinition|declared but not used" c := make(chan int) return c }(): diff --git a/test/fixedbugs/issue13471.go b/test/fixedbugs/issue13471.go index 0bfed42616..9bfc8c3d2c 100644 --- a/test/fixedbugs/issue13471.go +++ b/test/fixedbugs/issue13471.go @@ -9,17 +9,17 @@ package main func main() { - const _ int64 = 1e646456992 // ERROR "integer too large" - const _ int32 = 1e64645699 // ERROR "integer too large" - const _ int16 = 1e6464569 // ERROR "integer too large" - const _ int8 = 1e646456 // ERROR "integer too large" - const _ int = 1e64645 // ERROR "integer too large" + const _ int64 = 1e646456992 // ERROR "integer too large|floating-point constant truncated to integer" + const _ int32 = 1e64645699 // ERROR "integer too large|floating-point constant truncated to integer" + const _ int16 = 1e6464569 // ERROR "integer too large|floating-point constant truncated to integer" + const _ int8 = 1e646456 // ERROR "integer too large|floating-point constant truncated to integer" + const _ int = 1e64645 // ERROR "integer too large|floating-point constant truncated to integer" - const _ uint64 = 1e646456992 // ERROR "integer too large" - const _ uint32 = 1e64645699 // ERROR "integer too large" - const _ uint16 = 1e6464569 // ERROR "integer too large" - const _ uint8 = 1e646456 // ERROR "integer too large" - const _ uint = 1e64645 // ERROR "integer too large" + const _ uint64 = 1e646456992 // ERROR "integer too large|floating-point constant truncated to integer" + const _ uint32 = 1e64645699 // ERROR "integer too large|floating-point constant truncated to integer" + const _ uint16 = 1e6464569 // ERROR "integer too large|floating-point constant truncated to integer" + const _ uint8 = 1e646456 // ERROR "integer too large|floating-point constant truncated to integer" + const _ uint = 1e64645 // ERROR "integer too large|floating-point constant truncated to integer" - const _ rune = 1e64645 // ERROR "integer too large" + const _ rune = 1e64645 // ERROR "integer too large|floating-point constant truncated to integer" } diff --git a/test/fixedbugs/issue13821b.go b/test/fixedbugs/issue13821b.go index be67cea6dd..df68e8d626 100644 --- a/test/fixedbugs/issue13821b.go +++ b/test/fixedbugs/issue13821b.go @@ -15,10 +15,10 @@ var b B var b2 B2 var x1 = b && 1 < 2 // x1 has type B, not ideal bool var x2 = 1 < 2 && b // x2 has type B, not ideal bool -var x3 = b && b2 // ERROR "mismatched types B and B2" -var x4 = x1 && b2 // ERROR "mismatched types B and B2" -var x5 = x2 && b2 // ERROR "mismatched types B and B2" -var x6 = b2 && x1 // ERROR "mismatched types B2 and B" -var x7 = b2 && x2 // ERROR "mismatched types B2 and B" +var x3 = b && b2 // ERROR "mismatched types B and B2|incompatible types" +var x4 = x1 && b2 // ERROR "mismatched types B and B2|incompatible types" +var x5 = x2 && b2 // ERROR "mismatched types B and B2|incompatible types" +var x6 = b2 && x1 // ERROR "mismatched types B2 and B|incompatible types" +var x7 = b2 && x2 // ERROR "mismatched types B2 and B|incompatible types" -var x8 = b && !B2(true) // ERROR "mismatched types B and B2" +var x8 = b && !B2(true) // ERROR "mismatched types B and B2|incompatible types" diff --git a/test/fixedbugs/issue14006.go b/test/fixedbugs/issue14006.go index 02041cc290..9cad2b4c9d 100644 --- a/test/fixedbugs/issue14006.go +++ b/test/fixedbugs/issue14006.go @@ -21,26 +21,26 @@ func f() { var x int switch x { case 1: - 2: // ERROR "unexpected :" + 2: // ERROR "unexpected :|expected .*;.* or .*}.* or newline|value computed is not used" case 2: } switch x { case 1: - 2: ; // ERROR "unexpected :" + 2: ; // ERROR "unexpected :|expected .*;.* or .*}.* or newline|value computed is not used" case 2: } var y string switch y { case "foo": - "bar": // ERROR "unexpected :" + "bar": // ERROR "unexpected :|expected .*;.* or .*}.* or newline|value computed is not used" case "bar": } switch y { case "foo": - "bar": ; // ERROR "unexpected :" + "bar": ; // ERROR "unexpected :|expected .*;.* or .*}.* or newline|value computed is not used" case "bar": } @@ -56,12 +56,12 @@ func g() { var z bool switch { case z: - labelname: // ERROR "label labelname defined and not used" + labelname: // ERROR "label labelname defined and not used|previous definition|defined and not used" } switch { case z: - labelname: ; // ERROR "label labelname already defined at LINE-5" + labelname: ; // ERROR "label labelname already defined at LINE-5|label .*labelname.* already defined" case false: } -} \ No newline at end of file +} diff --git a/test/fixedbugs/issue14010.go b/test/fixedbugs/issue14010.go index 2786e107e8..0b233342be 100644 --- a/test/fixedbugs/issue14010.go +++ b/test/fixedbugs/issue14010.go @@ -10,6 +10,6 @@ package main func main() { - true = false // ERROR "cannot assign to true" - byte = 0 // ERROR "not an expression" + true = false // ERROR "cannot assign to true|invalid left hand side" + byte = 0 // ERROR "not an expression|invalid left hand side|invalid use of type" } diff --git a/test/fixedbugs/issue14321.go b/test/fixedbugs/issue14321.go index 058008c386..e1149c3f9d 100644 --- a/test/fixedbugs/issue14321.go +++ b/test/fixedbugs/issue14321.go @@ -27,7 +27,7 @@ type C struct { B } -var _ = C.F // ERROR "ambiguous selector" -var _ = C.G // ERROR "ambiguous selector" -var _ = C.H // ERROR "ambiguous selector" -var _ = C.I // ERROR "no method I" +var _ = C.F // ERROR "ambiguous" +var _ = C.G // ERROR "ambiguous" +var _ = C.H // ERROR "ambiguous" +var _ = C.I // ERROR "no method .*I.*" diff --git a/test/fixedbugs/issue8183.go b/test/fixedbugs/issue8183.go index 531dd4dbf8..caac667346 100644 --- a/test/fixedbugs/issue8183.go +++ b/test/fixedbugs/issue8183.go @@ -12,12 +12,12 @@ const ( ok = byte(iota + 253) bad barn - bard // ERROR "constant 256 overflows byte" + bard // ERROR "constant 256 overflows byte|integer constant overflow" ) const ( c = len([1 - iota]int{}) d - e // ERROR "array bound must be non-negative" - f // ERROR "array bound must be non-negative" + e // ERROR "array bound must be non-negative|negative array bound" + f // ERROR "array bound must be non-negative|negative array bound" ) diff --git a/test/fixedbugs/issue9036.go b/test/fixedbugs/issue9036.go index 38f06c30c8..e3d394f7f2 100644 --- a/test/fixedbugs/issue9036.go +++ b/test/fixedbugs/issue9036.go @@ -18,8 +18,8 @@ const ( ) const x4 = 0x1p10 // valid hexadecimal float -const x5 = 1p10 // ERROR "'p' exponent requires hexadecimal mantissa" -const x6 = 0P0 // ERROR "'P' exponent requires hexadecimal mantissa" +const x5 = 1p10 // ERROR "'p' exponent requires hexadecimal mantissa|invalid prefix" +const x6 = 0P0 // ERROR "'P' exponent requires hexadecimal mantissa|invalid prefix" func main() { fmt.Printf("%g %T\n", x1, x1) diff --git a/test/fixedbugs/issue9076.go b/test/fixedbugs/issue9076.go index 8daf12fee8..1613d5ede3 100644 --- a/test/fixedbugs/issue9076.go +++ b/test/fixedbugs/issue9076.go @@ -11,5 +11,5 @@ package main import "unsafe" const Hundred = 100 -var _ int32 = 100/unsafe.Sizeof(int(0)) + 1 // GC_ERROR "100 \/ unsafe.Sizeof\(int\(0\)\) \+ 1" -var _ int32 = Hundred/unsafe.Sizeof(int(0)) + 1 // GC_ERROR "Hundred \/ unsafe.Sizeof\(int\(0\)\) \+ 1" +var _ int32 = 100/unsafe.Sizeof(int(0)) + 1 // ERROR "100 \/ unsafe.Sizeof\(int\(0\)\) \+ 1|incompatible type" +var _ int32 = Hundred/unsafe.Sizeof(int(0)) + 1 // ERROR "Hundred \/ unsafe.Sizeof\(int\(0\)\) \+ 1|incompatible type" diff --git a/test/fixedbugs/issue9083.go b/test/fixedbugs/issue9083.go index 8fbd78be7a..d4762f802e 100644 --- a/test/fixedbugs/issue9083.go +++ b/test/fixedbugs/issue9083.go @@ -19,4 +19,5 @@ func main() { x = make(chan int) // ERROR "cannot use make\(chan int\)|incompatible" x = make(chan int, 0) // ERROR "cannot use make\(chan int, 0\)|incompatible" x = make(chan int, zero) // ERROR "cannot use make\(chan int, zero\)|incompatible" + _ = x } diff --git a/test/fixedbugs/issue9370.go b/test/fixedbugs/issue9370.go index 120af35397..6cc8d5b9e5 100644 --- a/test/fixedbugs/issue9370.go +++ b/test/fixedbugs/issue9370.go @@ -33,95 +33,95 @@ var ( var ( _ = e == c _ = e != c - _ = e >= c // ERROR "invalid operation.*not defined" + _ = e >= c // ERROR "invalid operation.*not defined|invalid comparison" _ = c == e _ = c != e - _ = c >= e // ERROR "invalid operation.*not defined" + _ = c >= e // ERROR "invalid operation.*not defined|invalid comparison" _ = i == c _ = i != c - _ = i >= c // ERROR "invalid operation.*not defined" + _ = i >= c // ERROR "invalid operation.*not defined|invalid comparison" _ = c == i _ = c != i - _ = c >= i // ERROR "invalid operation.*not defined" + _ = c >= i // ERROR "invalid operation.*not defined|invalid comparison" _ = e == n _ = e != n - _ = e >= n // ERROR "invalid operation.*not defined" + _ = e >= n // ERROR "invalid operation.*not defined|invalid comparison" _ = n == e _ = n != e - _ = n >= e // ERROR "invalid operation.*not defined" + _ = n >= e // ERROR "invalid operation.*not defined|invalid comparison" // i and n are not assignable to each other - _ = i == n // ERROR "invalid operation.*mismatched types" - _ = i != n // ERROR "invalid operation.*mismatched types" - _ = i >= n // ERROR "invalid operation.*mismatched types" - _ = n == i // ERROR "invalid operation.*mismatched types" - _ = n != i // ERROR "invalid operation.*mismatched types" - _ = n >= i // ERROR "invalid operation.*mismatched types" + _ = i == n // ERROR "invalid operation.*mismatched types|incompatible types" + _ = i != n // ERROR "invalid operation.*mismatched types|incompatible types" + _ = i >= n // ERROR "invalid operation.*mismatched types|incompatible types" + _ = n == i // ERROR "invalid operation.*mismatched types|incompatible types" + _ = n != i // ERROR "invalid operation.*mismatched types|incompatible types" + _ = n >= i // ERROR "invalid operation.*mismatched types|incompatible types" _ = e == 1 _ = e != 1 - _ = e >= 1 // ERROR "invalid operation.*not defined" + _ = e >= 1 // ERROR "invalid operation.*not defined|invalid comparison" _ = 1 == e _ = 1 != e - _ = 1 >= e // ERROR "invalid operation.*not defined" - - _ = i == 1 // ERROR "invalid operation.*mismatched types" - _ = i != 1 // ERROR "invalid operation.*mismatched types" - _ = i >= 1 // ERROR "invalid operation.*mismatched types" - _ = 1 == i // ERROR "invalid operation.*mismatched types" - _ = 1 != i // ERROR "invalid operation.*mismatched types" - _ = 1 >= i // ERROR "invalid operation.*mismatched types" - - _ = e == f // ERROR "invalid operation.*not defined" - _ = e != f // ERROR "invalid operation.*not defined" - _ = e >= f // ERROR "invalid operation.*not defined" - _ = f == e // ERROR "invalid operation.*not defined" - _ = f != e // ERROR "invalid operation.*not defined" - _ = f >= e // ERROR "invalid operation.*not defined" - - _ = i == f // ERROR "invalid operation.*mismatched types" - _ = i != f // ERROR "invalid operation.*mismatched types" - _ = i >= f // ERROR "invalid operation.*mismatched types" - _ = f == i // ERROR "invalid operation.*mismatched types" - _ = f != i // ERROR "invalid operation.*mismatched types" - _ = f >= i // ERROR "invalid operation.*mismatched types" - - _ = e == g // ERROR "invalid operation.*not defined" - _ = e != g // ERROR "invalid operation.*not defined" - _ = e >= g // ERROR "invalid operation.*not defined" - _ = g == e // ERROR "invalid operation.*not defined" - _ = g != e // ERROR "invalid operation.*not defined" - _ = g >= e // ERROR "invalid operation.*not defined" - - _ = i == g // ERROR "invalid operation.*not defined" - _ = i != g // ERROR "invalid operation.*not defined" - _ = i >= g // ERROR "invalid operation.*not defined" - _ = g == i // ERROR "invalid operation.*not defined" - _ = g != i // ERROR "invalid operation.*not defined" - _ = g >= i // ERROR "invalid operation.*not defined" - - _ = _ == e // ERROR "cannot use _ as value" - _ = _ == i // ERROR "cannot use _ as value" - _ = _ == c // ERROR "cannot use _ as value" - _ = _ == n // ERROR "cannot use _ as value" - _ = _ == f // ERROR "cannot use _ as value" - _ = _ == g // ERROR "cannot use _ as value" - - _ = e == _ // ERROR "cannot use _ as value" - _ = i == _ // ERROR "cannot use _ as value" - _ = c == _ // ERROR "cannot use _ as value" - _ = n == _ // ERROR "cannot use _ as value" - _ = f == _ // ERROR "cannot use _ as value" - _ = g == _ // ERROR "cannot use _ as value" - - _ = _ == _ // ERROR "cannot use _ as value" - - _ = e ^ c // ERROR "invalid operation.*mismatched types" - _ = c ^ e // ERROR "invalid operation.*mismatched types" - _ = 1 ^ e // ERROR "invalid operation.*mismatched types" - _ = e ^ 1 // ERROR "invalid operation.*mismatched types" + _ = 1 >= e // ERROR "invalid operation.*not defined|invalid comparison" + + _ = i == 1 // ERROR "invalid operation.*mismatched types|incompatible types" + _ = i != 1 // ERROR "invalid operation.*mismatched types|incompatible types" + _ = i >= 1 // ERROR "invalid operation.*mismatched types|incompatible types" + _ = 1 == i // ERROR "invalid operation.*mismatched types|incompatible types" + _ = 1 != i // ERROR "invalid operation.*mismatched types|incompatible types" + _ = 1 >= i // ERROR "invalid operation.*mismatched types|incompatible types" + + _ = e == f // ERROR "invalid operation.*not defined|invalid operation" + _ = e != f // ERROR "invalid operation.*not defined|invalid operation" + _ = e >= f // ERROR "invalid operation.*not defined|invalid comparison" + _ = f == e // ERROR "invalid operation.*not defined|invalid operation" + _ = f != e // ERROR "invalid operation.*not defined|invalid operation" + _ = f >= e // ERROR "invalid operation.*not defined|invalid comparison" + + _ = i == f // ERROR "invalid operation.*mismatched types|incompatible types" + _ = i != f // ERROR "invalid operation.*mismatched types|incompatible types" + _ = i >= f // ERROR "invalid operation.*mismatched types|incompatible types" + _ = f == i // ERROR "invalid operation.*mismatched types|incompatible types" + _ = f != i // ERROR "invalid operation.*mismatched types|incompatible types" + _ = f >= i // ERROR "invalid operation.*mismatched types|incompatible types" + + _ = e == g // ERROR "invalid operation.*not defined|invalid operation" + _ = e != g // ERROR "invalid operation.*not defined|invalid operation" + _ = e >= g // ERROR "invalid operation.*not defined|invalid comparison" + _ = g == e // ERROR "invalid operation.*not defined|invalid operation" + _ = g != e // ERROR "invalid operation.*not defined|invalid operation" + _ = g >= e // ERROR "invalid operation.*not defined|invalid comparison" + + _ = i == g // ERROR "invalid operation.*not defined|invalid operation" + _ = i != g // ERROR "invalid operation.*not defined|invalid operation" + _ = i >= g // ERROR "invalid operation.*not defined|invalid comparison" + _ = g == i // ERROR "invalid operation.*not defined|invalid operation" + _ = g != i // ERROR "invalid operation.*not defined|invalid operation" + _ = g >= i // ERROR "invalid operation.*not defined|invalid comparison" + + _ = _ == e // ERROR "cannot use .*_.* as value" + _ = _ == i // ERROR "cannot use .*_.* as value" + _ = _ == c // ERROR "cannot use .*_.* as value" + _ = _ == n // ERROR "cannot use .*_.* as value" + _ = _ == f // ERROR "cannot use .*_.* as value" + _ = _ == g // ERROR "cannot use .*_.* as value" + + _ = e == _ // ERROR "cannot use .*_.* as value" + _ = i == _ // ERROR "cannot use .*_.* as value" + _ = c == _ // ERROR "cannot use .*_.* as value" + _ = n == _ // ERROR "cannot use .*_.* as value" + _ = f == _ // ERROR "cannot use .*_.* as value" + _ = g == _ // ERROR "cannot use .*_.* as value" + + _ = _ == _ // ERROR "cannot use .*_.* as value" + + _ = e ^ c // ERROR "invalid operation.*mismatched types|incompatible types" + _ = c ^ e // ERROR "invalid operation.*mismatched types|incompatible types" + _ = 1 ^ e // ERROR "invalid operation.*mismatched types|incompatible types" + _ = e ^ 1 // ERROR "invalid operation.*mismatched types|incompatible types" _ = 1 ^ c _ = c ^ 1 ) -- cgit v1.3 From 14305527f686ced0de8d08b3a62bd96fe6359481 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 10 Dec 2020 12:21:45 -0800 Subject: cmd/compile: fix select statement evaluation order corner case The Go spec requires that select case clauses be evaluated in order, which is stricter than normal ordering semantics. cmd/compile handled this correctly for send clauses, but was not correctly handling receive clauses that involved bare variable references. Discovered with @cuonglm. Fixes #43111. Change-Id: Iec93b6514dd771875b084ba49c15d7f4531b4a6f Reviewed-on: https://go-review.googlesource.com/c/go/+/277132 Trust: Matthew Dempsky Run-TryBot: Matthew Dempsky TryBot-Result: Go Bot Reviewed-by: Cuong Manh Le Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/order.go | 2 +- test/fixedbugs/issue43111.go | 70 ++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue43111.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go index 863de5b6c7..30e1535c09 100644 --- a/src/cmd/compile/internal/gc/order.go +++ b/src/cmd/compile/internal/gc/order.go @@ -891,7 +891,7 @@ func (o *Order) stmt(n *Node) { // c is always evaluated; x and ok are only evaluated when assigned. r.Right.Left = o.expr(r.Right.Left, nil) - if r.Right.Left.Op != ONAME { + if !r.Right.Left.IsAutoTmp() { r.Right.Left = o.copyExpr(r.Right.Left, r.Right.Left.Type, false) } diff --git a/test/fixedbugs/issue43111.go b/test/fixedbugs/issue43111.go new file mode 100644 index 0000000000..76d7beb084 --- /dev/null +++ b/test/fixedbugs/issue43111.go @@ -0,0 +1,70 @@ +// run + +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +var ch chan int +var x int + +func f() int { + close(ch) + ch = nil + return 0 +} + +func g() int { + ch = nil + x = 0 + return 0 +} + +func main() { + var nilch chan int + var v int + var ok bool + _, _ = v, ok + + ch = make(chan int) + select { + case <-ch: + case nilch <- f(): + } + + ch = make(chan int) + select { + case v = <-ch: + case nilch <- f(): + } + + ch = make(chan int) + select { + case v := <-ch: _ = v + case nilch <- f(): + } + + ch = make(chan int) + select { + case v, ok = <-ch: + case nilch <- f(): + } + + ch = make(chan int) + select { + case v, ok := <-ch: _, _ = v, ok + case nilch <- f(): + } + + ch1 := make(chan int, 1) + ch = ch1 + x = 42 + select { + case ch <- x: + case nilch <- g(): + } + if got := <-ch1; got != 42 { + panic(got) + } +} -- cgit v1.3 From 0a02371b0576964e81c3b40d328db9a3ef3b031b Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Mon, 14 Dec 2020 09:45:44 +0700 Subject: cmd/compile: set correct type for OpIData MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since CL 270057, there're many attempts to fix the expand_calls pass with interface{}-typed. But all of them did not fix the root cause. The main issue is during SSA conversion in gc/ssa.go, for empty interface case, we make its type as n.Type, instead of BytePtr. To fix these, we can just use BytePtr for now, since when itab fields are treated as scalar. No significal changes on compiler speed, size. cmd/compile/internal/ssa expandCalls.func6 9488 -> 9232 (-2.70%) file before after Δ % cmd/compile/internal/ssa.s 3992893 3992637 -256 -0.006% total 20500447 20500191 -256 -0.001% Fixes #43112 Updates #42784 Updates #42727 Updates #42568 Change-Id: I0b15d9434e0be5448453e61f98ef9c2d6cd93792 Reviewed-on: https://go-review.googlesource.com/c/go/+/276952 Trust: Cuong Manh Le Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/ssa.go | 4 +-- src/cmd/compile/internal/ssa/expand_calls.go | 8 +----- test/fixedbugs/issue43112.go | 41 ++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 test/fixedbugs/issue43112.go (limited to 'test/fixedbugs') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 65b9291b76..5b74754b53 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -5925,7 +5925,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) { // Load type out of itab, build interface with existing idata. off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), itab) typ := s.load(byteptr, off) - idata := s.newValue1(ssa.OpIData, n.Type, iface) + idata := s.newValue1(ssa.OpIData, byteptr, iface) res = s.newValue2(ssa.OpIMake, n.Type, typ, idata) return } @@ -5947,7 +5947,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) { bOk.AddEdgeTo(bEnd) bFail.AddEdgeTo(bEnd) s.startBlock(bEnd) - idata := s.newValue1(ssa.OpIData, n.Type, iface) + idata := s.newValue1(ssa.OpIData, byteptr, iface) res = s.newValue2(ssa.OpIMake, n.Type, s.variable(&typVar, byteptr), idata) resok = cond delete(s.vars, &typVar) diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index f266e49327..fbde19d94c 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -196,9 +196,6 @@ func expandCalls(f *Func) { } if leaf.Op == OpIData { leafType = removeTrivialWrapperTypes(leaf.Type) - if leafType.IsEmptyInterface() { - leafType = typ.BytePtr - } } aux := selector.Aux auxInt := selector.AuxInt + offset @@ -247,12 +244,9 @@ func expandCalls(f *Func) { // i.e., the struct select is generated and remains in because it is not applied to an actual structure. // The OpLoad was created to load the single field of the IData // This case removes that StructSelect. - if leafType != selector.Type && !selector.Type.IsEmptyInterface() { // empty interface for #42727 + if leafType != selector.Type { f.Fatalf("Unexpected Load as selector, leaf=%s, selector=%s\n", leaf.LongString(), selector.LongString()) } - if selector.Type.IsEmptyInterface() { - selector.Type = typ.BytePtr - } leaf.copyOf(selector) for _, s := range namedSelects[selector] { locs = append(locs, f.Names[s.locIndex]) diff --git a/test/fixedbugs/issue43112.go b/test/fixedbugs/issue43112.go new file mode 100644 index 0000000000..e36627a015 --- /dev/null +++ b/test/fixedbugs/issue43112.go @@ -0,0 +1,41 @@ +// compile + +// Copyright 2020 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 p + +type Symbol interface{} + +type Value interface { + String() string +} + +type Object interface { + String() string +} + +type Scope struct { + outer *Scope + elems map[string]Object +} + +func (s *Scope) findouter(name string) (*Scope, Object) { + return s.outer.findouter(name) +} + +func (s *Scope) Resolve(name string) (sym Symbol) { + if _, obj := s.findouter(name); obj != nil { + sym = obj.(Symbol) + } + return +} + +type ScopeName struct { + scope *Scope +} + +func (n *ScopeName) Get(name string) (Value, error) { + return n.scope.Resolve(name).(Value), nil +} -- cgit v1.3