diff options
author | Patrice Arruda <patricearruda@google.com> | 2020-06-25 11:55:41 -0700 |
---|---|---|
committer | Patrice Arruda <patricearruda@google.com> | 2020-06-25 12:25:24 -0700 |
commit | 7f4776e1ddb05395a4025a30de8d7b78d62ac9aa (patch) | |
tree | a4ac4cdd694b156cc15be3c7c18bfd92db1fefdd /test | |
parent | 3affa1d2632b48f9589ab4c91ca1b825d7c73a87 (diff) | |
download | platform_prebuilts_go_linux-x86-7f4776e1ddb05395a4025a30de8d7b78d62ac9aa.tar.gz platform_prebuilts_go_linux-x86-7f4776e1ddb05395a4025a30de8d7b78d62ac9aa.tar.bz2 platform_prebuilts_go_linux-x86-7f4776e1ddb05395a4025a30de8d7b78d62ac9aa.zip |
Update linux go to 1.15beta1android-r-beta-3android-r-beta-2
From https://ci.android.com/builds/submitted/6626886/linux/latest/go.zip
Test: m blueprint_tools
Change-Id: Ib0d1176e769611b25554177aef209bc7e6456694
Diffstat (limited to 'test')
242 files changed, 5933 insertions, 6433 deletions
diff --git a/test/blank1.go b/test/blank1.go index 1a9f0124..c9a8e6a2 100644 --- a/test/blank1.go +++ b/test/blank1.go @@ -4,7 +4,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Test that incorrect uses of the blank identifer are caught. +// Test that incorrect uses of the blank identifier are caught. // Does not compile. package _ // ERROR "invalid package name" diff --git a/test/chan/powser1.go b/test/chan/powser1.go index 5357eec5..e999dde2 100644 --- a/test/chan/powser1.go +++ b/test/chan/powser1.go @@ -595,7 +595,7 @@ func Subst(U, V PS) PS { return Z } -// Monomial Substition: U(c x^n) +// Monomial Substitution: U(c x^n) // Each Ui is multiplied by c^i and followed by n-1 zeros func MonSubst(U PS, c0 rat, n int) PS { diff --git a/test/chan/powser2.go b/test/chan/powser2.go index fb1fb851..72cbba8c 100644 --- a/test/chan/powser2.go +++ b/test/chan/powser2.go @@ -609,7 +609,7 @@ func Subst(U, V PS) PS { return Z } -// Monomial Substition: U(c x^n) +// Monomial Substitution: U(c x^n) // Each Ui is multiplied by c^i and followed by n-1 zeros func MonSubst(U PS, c0 *rat, n int) PS { diff --git a/test/chanlinear.go b/test/chanlinear.go index 55fee4ab..4d55586d 100644 --- a/test/chanlinear.go +++ b/test/chanlinear.go @@ -5,7 +5,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Test that dequeueing from a pending channel doesn't +// Test that dequeuing from a pending channel doesn't // take linear time. package main diff --git a/test/closure2.go b/test/closure2.go index 4d61b45d..e4db05d8 100644 --- a/test/closure2.go +++ b/test/closure2.go @@ -74,7 +74,7 @@ func main() { for i := range [2]int{} { if i == 0 { g = func() int { - return i // test that we capture by ref here, i is mutated on every interation + return i // test that we capture by ref here, i is mutated on every interaction } } } @@ -90,7 +90,7 @@ func main() { q++ g = func() int { return q // test that we capture by ref here - // q++ must on a different decldepth than q declaration + // q++ must on a different decldepth than q declaration } } if g() != 2 { @@ -108,7 +108,7 @@ func main() { }()] = range [2]int{} { g = func() int { return q // test that we capture by ref here - // q++ must on a different decldepth than q declaration + // q++ must on a different decldepth than q declaration } } if g() != 2 { diff --git a/test/codegen/README b/test/codegen/README index 298d807b..b803fe58 100644 --- a/test/codegen/README +++ b/test/codegen/README @@ -9,17 +9,22 @@ compiler. - Introduction The test harness compiles Go code inside files in this directory and -then matches the generated assembly (the output of `go tool compile -S`) -against a set of regexps specified in comments that follow a special -syntax (described below). The test driver is implemented as a step of -the top-level test/run.go suite, called "asmcheck". +matches the generated assembly (the output of `go tool compile -S`) +against a set of regexps to be specified in comments that follow a +special syntax (described below). The test driver is implemented as a +step of the top-level test/run.go suite, called "asmcheck". -The codegen tests run during all.bash, but can also be run in -isolation by using +The codegen harness is part of the all.bash test suite, but for +performance reasons only the codegen tests for the host machine's +GOARCH are enabled by default, and only on GOOS=linux. - $ ../bin/go run run.go -v codegen +To perform comprehensive tests for all the supported architectures +(even on a non-Linux system), one can run the following command -in the top-level test directory. + $ ../bin/go run run.go -all_codegen -v codegen + +in the top-level test directory. This is recommended after any change +that affect the compiler's code. The test harness compiles the tests with the same go toolchain that is used to run run.go. After writing tests for a newly added codegen @@ -94,6 +99,7 @@ For example: verifies that NO memmove call is present in the assembly generated for the copy() line. + - Architecture specifiers There are three different ways to specify on which architecture a test @@ -121,7 +127,7 @@ As a general guideline, test functions should be small, to avoid possible interactions between unrelated lines of code that may be introduced, for example, by the compiler's optimization passes. -Any given line of Go code could get assigned more instructions that it +Any given line of Go code could get assigned more instructions than it may appear from reading the source. In particular, matching all MOV instructions should be avoided; the compiler may add them for unrelated reasons and this may render the test ineffective. diff --git a/test/codegen/addrcalc.go b/test/codegen/addrcalc.go new file mode 100644 index 00000000..45552d27 --- /dev/null +++ b/test/codegen/addrcalc.go @@ -0,0 +1,14 @@ +// asmcheck + +// 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. + +package codegen + +// Make sure we use ADDQ instead of LEAQ when we can. + +func f(p *[4][2]int, x int) *int { + // amd64:"ADDQ",-"LEAQ" + return &p[x][0] +} diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go index dcbc6d3f..8f259743 100644 --- a/test/codegen/arithmetic.go +++ b/test/codegen/arithmetic.go @@ -188,14 +188,24 @@ func Pow2Mods(n1 uint, n2 int) (uint, int) { } // Check that signed divisibility checks get converted to AND on low bits -func Pow2DivisibleSigned(n int) bool { +func Pow2DivisibleSigned(n1, n2 int) (bool, bool) { // 386:"TESTL\t[$]63",-"DIVL",-"SHRL" // amd64:"TESTQ\t[$]63",-"DIVQ",-"SHRQ" // arm:"AND\t[$]63",-".*udiv",-"SRA" // arm64:"AND\t[$]63",-"UDIV",-"ASR" // ppc64:"ANDCC\t[$]63",-"SRAD" // ppc64le:"ANDCC\t[$]63",-"SRAD" - return n%64 == 0 // signed + a := n1%64 == 0 // signed divisible + + // 386:"TESTL\t[$]63",-"DIVL",-"SHRL" + // amd64:"TESTQ\t[$]63",-"DIVQ",-"SHRQ" + // arm:"AND\t[$]63",-".*udiv",-"SRA" + // arm64:"AND\t[$]63",-"UDIV",-"ASR" + // ppc64:"ANDCC\t[$]63",-"SRAD" + // ppc64le:"ANDCC\t[$]63",-"SRAD" + b := n2%64 != 0 // signed indivisible + + return a, b } // Check that constant modulo divs get turned into MULs @@ -441,3 +451,14 @@ func addSpecial(a, b, c uint32) (uint32, uint32, uint32) { c += 128 return a, b, c } + + +// Divide -> shift rules usually require fixup for negative inputs. +// If the input is non-negative, make sure the fixup is eliminated. +func divInt(v int64) int64 { + if v < 0 { + return 0 + } + // amd64:-`.*SARQ.*63,`, -".*SHRQ", ".*SARQ.*[$]9," + return v / 512 +} diff --git a/test/codegen/bits.go b/test/codegen/bits.go index 65d57c8f..0a5428b5 100644 --- a/test/codegen/bits.go +++ b/test/codegen/bits.go @@ -278,6 +278,11 @@ func bitOpOnMem(a []uint32) { a[5] ^= 0x2000 } +func bitcheckMostNegative(b uint8) bool { + // amd64:"TESTB" + return b&0x80 == 0x80 +} + // Check AND masking on arm64 (Issue #19857) func and_mask_1(a uint64) uint64 { @@ -314,3 +319,15 @@ func op_orn(x, y uint32) uint32 { // arm64:`ORN\t`,-`ORR` return x | ^y } + +// check bitsets +func bitSetPowerOf2Test(x int) bool { + // amd64:"BTL\t[$]3" + return x&8 == 8 +} + +func bitSetTest(x int) bool { + // amd64:"ANDQ\t[$]9, AX" + // amd64:"CMPQ\tAX, [$]9" + return x&9 == 9 +} diff --git a/test/codegen/bool.go b/test/codegen/bool.go new file mode 100644 index 00000000..929b1b49 --- /dev/null +++ b/test/codegen/bool.go @@ -0,0 +1,33 @@ +// asmcheck + +// 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 codegen + +// This file contains codegen tests related to boolean simplifications/optimizations. + +func convertNeq0B(x uint8, c bool) bool { + // amd64:"ANDL\t[$]1",-"SETNE" + b := x&1 != 0 + return c && b +} + +func convertNeq0W(x uint16, c bool) bool { + // amd64:"ANDL\t[$]1",-"SETNE" + b := x&1 != 0 + return c && b +} + +func convertNeq0L(x uint32, c bool) bool { + // amd64:"ANDL\t[$]1",-"SETB" + b := x&1 != 0 + return c && b +} + +func convertNeq0Q(x uint64, c bool) bool { + // amd64:"ANDQ\t[$]1",-"SETB" + b := x&1 != 0 + return c && b +} diff --git a/test/codegen/compare_and_branch.go b/test/codegen/compare_and_branch.go new file mode 100644 index 00000000..696a2d5f --- /dev/null +++ b/test/codegen/compare_and_branch.go @@ -0,0 +1,206 @@ +// asmcheck + +// 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. + +package codegen + +//go:noinline +func dummy() {} + +// Signed 64-bit compare-and-branch. +func si64(x, y chan int64) { + // s390x:"CGRJ\t[$](2|4), R[0-9]+, R[0-9]+, " + for <-x < <-y { + dummy() + } + + // s390x:"CL?GRJ\t[$]8, R[0-9]+, R[0-9]+, " + for <-x == <-y { + dummy() + } +} + +// Signed 64-bit compare-and-branch with 8-bit immediate. +func si64x8() { + // s390x:"CGIJ\t[$]12, R[0-9]+, [$]127, " + for i := int64(0); i < 128; i++ { + dummy() + } + + // s390x:"CGIJ\t[$]10, R[0-9]+, [$]-128, " + for i := int64(0); i > -129; i-- { + dummy() + } + + // s390x:"CGIJ\t[$]2, R[0-9]+, [$]127, " + for i := int64(0); i >= 128; i++ { + dummy() + } + + // s390x:"CGIJ\t[$]4, R[0-9]+, [$]-128, " + for i := int64(0); i <= -129; i-- { + dummy() + } +} + +// Unsigned 64-bit compare-and-branch. +func ui64(x, y chan uint64) { + // s390x:"CLGRJ\t[$](2|4), R[0-9]+, R[0-9]+, " + for <-x > <-y { + dummy() + } + + // s390x:"CL?GRJ\t[$]6, R[0-9]+, R[0-9]+, " + for <-x != <-y { + dummy() + } +} + +// Unsigned 64-bit comparison with 8-bit immediate. +func ui64x8() { + // s390x:"CLGIJ\t[$]4, R[0-9]+, [$]128, " + for i := uint64(0); i < 128; i++ { + dummy() + } + + // s390x:"CLGIJ\t[$]12, R[0-9]+, [$]255, " + for i := uint64(0); i < 256; i++ { + dummy() + } + + // s390x:"CLGIJ\t[$]2, R[0-9]+, [$]255, " + for i := uint64(0); i >= 256; i-- { + dummy() + } + + // s390x:"CLGIJ\t[$]2, R[0-9]+, [$]0, " + for i := uint64(1024); i > 0; i-- { + dummy() + } +} + +// Signed 32-bit compare-and-branch. +func si32(x, y chan int32) { + // s390x:"CRJ\t[$](2|4), R[0-9]+, R[0-9]+, " + for <-x < <-y { + dummy() + } + + // s390x:"CL?RJ\t[$]8, R[0-9]+, R[0-9]+, " + for <-x == <-y { + dummy() + } +} + +// Signed 32-bit compare-and-branch with 8-bit immediate. +func si32x8() { + // s390x:"CIJ\t[$]12, R[0-9]+, [$]127, " + for i := int32(0); i < 128; i++ { + dummy() + } + + // s390x:"CIJ\t[$]10, R[0-9]+, [$]-128, " + for i := int32(0); i > -129; i-- { + dummy() + } + + // s390x:"CIJ\t[$]2, R[0-9]+, [$]127, " + for i := int32(0); i >= 128; i++ { + dummy() + } + + // s390x:"CIJ\t[$]4, R[0-9]+, [$]-128, " + for i := int32(0); i <= -129; i-- { + dummy() + } +} + +// Unsigned 32-bit compare-and-branch. +func ui32(x, y chan uint32) { + // s390x:"CLRJ\t[$](2|4), R[0-9]+, R[0-9]+, " + for <-x > <-y { + dummy() + } + + // s390x:"CL?RJ\t[$]6, R[0-9]+, R[0-9]+, " + for <-x != <-y { + dummy() + } +} + +// Unsigned 32-bit comparison with 8-bit immediate. +func ui32x8() { + // s390x:"CLIJ\t[$]4, R[0-9]+, [$]128, " + for i := uint32(0); i < 128; i++ { + dummy() + } + + // s390x:"CLIJ\t[$]12, R[0-9]+, [$]255, " + for i := uint32(0); i < 256; i++ { + dummy() + } + + // s390x:"CLIJ\t[$]2, R[0-9]+, [$]255, " + for i := uint32(0); i >= 256; i-- { + dummy() + } + + // s390x:"CLIJ\t[$]2, R[0-9]+, [$]0, " + for i := uint32(1024); i > 0; i-- { + dummy() + } +} + +// Signed 64-bit comparison with unsigned 8-bit immediate. +func si64xu8(x chan int64) { + // s390x:"CLGIJ\t[$]8, R[0-9]+, [$]128, " + for <-x == 128 { + dummy() + } + + // s390x:"CLGIJ\t[$]6, R[0-9]+, [$]255, " + for <-x != 255 { + dummy() + } +} + +// Signed 32-bit comparison with unsigned 8-bit immediate. +func si32xu8(x chan int32) { + // s390x:"CLIJ\t[$]8, R[0-9]+, [$]255, " + for <-x == 255 { + dummy() + } + + // s390x:"CLIJ\t[$]6, R[0-9]+, [$]128, " + for <-x != 128 { + dummy() + } +} + +// Unsigned 64-bit comparison with signed 8-bit immediate. +func ui64xu8(x chan uint64) { + // s390x:"CGIJ\t[$]8, R[0-9]+, [$]-1, " + for <-x == ^uint64(0) { + dummy() + } + + // s390x:"CGIJ\t[$]6, R[0-9]+, [$]-128, " + for <-x != ^uint64(127) { + dummy() + } +} + +// Unsigned 32-bit comparison with signed 8-bit immediate. +func ui32xu8(x chan uint32) { + // s390x:"CIJ\t[$]8, R[0-9]+, [$]-128, " + for <-x == ^uint32(127) { + dummy() + } + + // s390x:"CIJ\t[$]6, R[0-9]+, [$]-1, " + for <-x != ^uint32(0) { + dummy() + } +} diff --git a/test/codegen/comparisons.go b/test/codegen/comparisons.go index 62ba184e..90808573 100644 --- a/test/codegen/comparisons.go +++ b/test/codegen/comparisons.go @@ -215,31 +215,195 @@ func CmpLogicalToZero(a, b, c uint32, d, e uint64) uint64 { // ppc64:"ANDCC",-"CMPW" // ppc64le:"ANDCC",-"CMPW" + // wasm:"I64Eqz",-"I32Eqz",-"I64ExtendI32U",-"I32WrapI64" if a&63 == 0 { return 1 } // ppc64:"ANDCC",-"CMP" // ppc64le:"ANDCC",-"CMP" + // wasm:"I64Eqz",-"I32Eqz",-"I64ExtendI32U",-"I32WrapI64" if d&255 == 0 { return 1 } // ppc64:"ANDCC",-"CMP" // ppc64le:"ANDCC",-"CMP" + // wasm:"I64Eqz",-"I32Eqz",-"I64ExtendI32U",-"I32WrapI64" if d&e == 0 { return 1 } // ppc64:"ORCC",-"CMP" // ppc64le:"ORCC",-"CMP" + // wasm:"I64Eqz",-"I32Eqz",-"I64ExtendI32U",-"I32WrapI64" if d|e == 0 { return 1 } // ppc64:"XORCC",-"CMP" // ppc64le:"XORCC",-"CMP" + // wasm:"I64Eqz","I32Eqz",-"I64ExtendI32U",-"I32WrapI64" if e^d == 0 { return 1 } return 0 } + +// The following CmpToZero_ex* check that cmp|cmn with bmi|bpl are generated for +// 'comparing to zero' expressions + +// var + const +// 'x-const' might be canonicalized to 'x+(-const)', so we check both +// CMN and CMP for subtraction expressions to make the pattern robust. +func CmpToZero_ex1(a int64, e int32) int { + // arm64:`CMN`,-`ADD`,`(BMI|BPL)` + if a+3 < 0 { + return 1 + } + + // arm64:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)` + if a+5 <= 0 { + return 1 + } + + // arm64:`CMN`,-`ADD`,`(BMI|BPL)` + if a+13 >= 0 { + return 2 + } + + // arm64:`CMP|CMN`,-`(ADD|SUB)`,`(BMI|BPL)` + if a-7 < 0 { + return 3 + } + + // arm64:`CMP|CMN`,-`(ADD|SUB)`,`(BMI|BPL)` + if a-11 >= 0 { + return 4 + } + + // arm64:`CMP|CMN`,-`(ADD|SUB)`,`BEQ`,`(BMI|BPL)` + if a-19 > 0 { + return 4 + } + + // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)` + // arm:`CMN`,-`ADD`,`(BMI|BPL)` + if e+3 < 0 { + return 5 + } + + // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)` + // arm:`CMN`,-`ADD`,`(BMI|BPL)` + if e+13 >= 0 { + return 6 + } + + // arm64:`CMPW|CMNW`,`(BMI|BPL)` + // arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)` + if e-7 < 0 { + return 7 + } + + // arm64:`CMPW|CMNW`,`(BMI|BPL)` + // arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)` + if e-11 >= 0 { + return 8 + } + + return 0 +} + +// var + var +// TODO: optimize 'var - var' +func CmpToZero_ex2(a, b, c int64, e, f, g int32) int { + // arm64:`CMN`,-`ADD`,`(BMI|BPL)` + if a+b < 0 { + return 1 + } + + // arm64:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)` + if a+c <= 0 { + return 1 + } + + // arm64:`CMN`,-`ADD`,`(BMI|BPL)` + if b+c >= 0 { + return 2 + } + + // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)` + // arm:`CMN`,-`ADD`,`(BMI|BPL)` + if e+f < 0 { + return 5 + } + + // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)` + // arm:`CMN`,-`ADD`,`(BMI|BPL)` + if f+g >= 0 { + return 6 + } + return 0 +} + +// var + var*var +func CmpToZero_ex3(a, b, c, d int64, e, f, g, h int32) int { + // arm64:`CMN`,-`MADD`,`MUL`,`(BMI|BPL)` + if a+b*c < 0 { + return 1 + } + + // arm64:`CMN`,-`MADD`,`MUL`,`(BMI|BPL)` + if b+c*d >= 0 { + return 2 + } + + // arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)` + // arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)` + if e+f*g > 0 { + return 5 + } + + // arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)` + // arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)` + if f+g*h <= 0 { + return 6 + } + return 0 +} + +// var - var*var +func CmpToZero_ex4(a, b, c, d int64, e, f, g, h int32) int { + // arm64:`CMP`,-`MSUB`,`MUL`,`BEQ`,`(BMI|BPL)` + if a-b*c > 0 { + return 1 + } + + // arm64:`CMP`,-`MSUB`,`MUL`,`(BMI|BPL)` + if b-c*d >= 0 { + return 2 + } + + // arm64:`CMPW`,-`MSUBW`,`MULW`,`(BMI|BPL)` + if e-f*g < 0 { + return 5 + } + + // arm64:`CMPW`,-`MSUBW`,`MULW`,`(BMI|BPL)` + if f-g*h >= 0 { + return 6 + } + return 0 +} + +func CmpToZero_ex5(e, f int32, u uint32) int { + // arm:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)` + if e+f<<1 > 0 { + return 1 + } + + // arm:`CMP`,-`SUB`,`(BMI|BPL)` + if f-int32(u>>2) >= 0 { + return 2 + } + return 0 +} diff --git a/test/codegen/condmove.go b/test/codegen/condmove.go index 3690a546..f86da345 100644 --- a/test/codegen/condmove.go +++ b/test/codegen/condmove.go @@ -13,6 +13,7 @@ func cmovint(c int) int { } // amd64:"CMOVQLT" // arm64:"CSEL\tLT" + // wasm:"Select" return x } @@ -22,6 +23,7 @@ func cmovchan(x, y chan int) chan int { } // amd64:"CMOVQNE" // arm64:"CSEL\tNE" + // wasm:"Select" return x } @@ -30,7 +32,8 @@ func cmovuintptr(x, y uintptr) uintptr { x = -y } // amd64:"CMOVQCS" - // arm64:"CSEL\tLO" + // arm64:"CSEL\t(LO|HI)" + // wasm:"Select" return x } @@ -39,7 +42,8 @@ func cmov32bit(x, y uint32) uint32 { x = -y } // amd64:"CMOVLCS" - // arm64:"CSEL\tLO" + // arm64:"CSEL\t(LO|HI)" + // wasm:"Select" return x } @@ -48,7 +52,8 @@ func cmov16bit(x, y uint16) uint16 { x = -y } // amd64:"CMOVWCS" - // arm64:"CSEL\tLO" + // arm64:"CSEL\t(LO|HI)" + // wasm:"Select" return x } @@ -61,6 +66,7 @@ func cmovfloateq(x, y float64) int { } // amd64:"CMOVQNE","CMOVQPC" // arm64:"CSEL\tEQ" + // wasm:"Select" return a } @@ -71,6 +77,7 @@ func cmovfloatne(x, y float64) int { } // amd64:"CMOVQNE","CMOVQPS" // arm64:"CSEL\tNE" + // wasm:"Select" return a } @@ -96,7 +103,8 @@ func cmovfloatint2(x, y float64) float64 { } // amd64:"CMOVQHI" // arm64:"CSEL\tMI" - r = r - ldexp(y, (rexp-yexp)) + // wasm:"Select" + r = r - ldexp(y, rexp-yexp) } return r } @@ -109,6 +117,7 @@ func cmovloaded(x [4]int, y int) int { } // amd64:"CMOVQNE" // arm64:"CSEL\tNE" + // wasm:"Select" return y } @@ -119,6 +128,7 @@ func cmovuintptr2(x, y uintptr) uintptr { } // amd64:"CMOVQEQ" // arm64:"CSEL\tEQ" + // wasm:"Select" return a } @@ -130,6 +140,7 @@ func cmovfloatmove(x, y int) float64 { } // amd64:-"CMOV" // arm64:-"CSEL" + // wasm:-"Select" return a } diff --git a/test/codegen/copy.go b/test/codegen/copy.go index 46c2bde9..0cd86d11 100644 --- a/test/codegen/copy.go +++ b/test/codegen/copy.go @@ -34,6 +34,8 @@ func movesmall7() { func movesmall16() { x := [...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} // amd64:-".*memmove" + // ppc64:".*memmove" + // ppc64le:".*memmove" copy(x[1:], x[:]) } @@ -41,10 +43,34 @@ var x [256]byte // Check that large disjoint copies are replaced with moves. +func moveDisjointStack32() { + var s [32]byte + // ppc64:-".*memmove" + // ppc64le:-".*memmove" + // ppc64le/power8:"LXVD2X",-"ADD",-"BC" + // ppc64le/power9:"LXV",-"LXVD2X",-"ADD",-"BC" + copy(s[:], x[:32]) + runtime.KeepAlive(&s) +} + +func moveDisjointStack64() { + var s [96]byte + // ppc64:-".*memmove" + // ppc64le:-".*memmove" + // ppc64le/power8:"LXVD2X","ADD","BC" + // ppc64le/power9:"LXV",-"LXVD2X",-"ADD",-"BC" + copy(s[:], x[:96]) + runtime.KeepAlive(&s) +} + func moveDisjointStack() { var s [256]byte // s390x:-".*memmove" // amd64:-".*memmove" + // ppc64:-".*memmove" + // ppc64le:-".*memmove" + // ppc64le/power8:"LXVD2X" + // ppc64le/power9:"LXV",-"LXVD2X" copy(s[:], x[:]) runtime.KeepAlive(&s) } @@ -53,6 +79,10 @@ func moveDisjointArg(b *[256]byte) { var s [256]byte // s390x:-".*memmove" // amd64:-".*memmove" + // ppc64:-".*memmove" + // ppc64le:-".*memmove" + // ppc64le/power8:"LXVD2X" + // ppc64le/power9:"LXV",-"LXVD2X" copy(s[:], b[:]) runtime.KeepAlive(&s) } @@ -60,6 +90,10 @@ func moveDisjointArg(b *[256]byte) { func moveDisjointNoOverlap(a *[256]byte) { // s390x:-".*memmove" // amd64:-".*memmove" + // ppc64:-".*memmove" + // ppc64le:-".*memmove" + // ppc64le/power8:"LXVD2X" + // ppc64le/power9:"LXV",-"LXVD2X" copy(a[:], a[128:]) } diff --git a/test/codegen/floats.go b/test/codegen/floats.go index 7ec36549..3fae1a32 100644 --- a/test/codegen/floats.go +++ b/test/codegen/floats.go @@ -118,10 +118,32 @@ func FusedSub64_b(x, y, z float64) float64 { } func Cmp(f float64) bool { - // arm64:"FCMPD","BLE",-"CSET\tGT",-"CBZ" + // arm64:"FCMPD","(BGT|BLE|BMI|BPL)",-"CSET\tGT",-"CBZ" return f > 4 || f < -4 } +func CmpZero64(f float64) bool { + // s390x:"LTDBR",-"FCMPU" + return f <= 0 +} + +func CmpZero32(f float32) bool { + // s390x:"LTEBR",-"CEBR" + return f <= 0 +} + +func CmpWithSub(a float64, b float64) bool { + f := a - b + // s390x:-"LTDBR" + return f <= 0 +} + +func CmpWithAdd(a float64, b float64) bool { + f := a + b + // s390x:-"LTDBR" + return f <= 0 +} + // ---------------- // // Non-floats // // ---------------- // diff --git a/test/codegen/fuse.go b/test/codegen/fuse.go new file mode 100644 index 00000000..79dd337d --- /dev/null +++ b/test/codegen/fuse.go @@ -0,0 +1,197 @@ +// asmcheck + +// 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. + +package codegen + +// Notes: +// - these examples use channels to provide a source of +// unknown values that cannot be optimized away +// - these examples use for loops to force branches +// backward (predicted taken) + +// ---------------------------------- // +// signed integer range (conjunction) // +// ---------------------------------- // + +func si1c(c <-chan int64) { + // amd64:"CMPQ\t.+, [$]256" + // s390x:"CLGIJ\t[$]12, R[0-9]+, [$]255" + for x := <-c; x >= 0 && x < 256; x = <-c { + } +} + +func si2c(c <-chan int32) { + // amd64:"CMPL\t.+, [$]256" + // s390x:"CLIJ\t[$]12, R[0-9]+, [$]255" + for x := <-c; x >= 0 && x < 256; x = <-c { + } +} + +func si3c(c <-chan int16) { + // amd64:"CMPW\t.+, [$]256" + // s390x:"CLIJ\t[$]12, R[0-9]+, [$]255" + for x := <-c; x >= 0 && x < 256; x = <-c { + } +} + +func si4c(c <-chan int8) { + // amd64:"CMPB\t.+, [$]10" + // s390x:"CLIJ\t[$]4, R[0-9]+, [$]10" + for x := <-c; x >= 0 && x < 10; x = <-c { + } +} + +func si5c(c <-chan int64) { + // amd64:"CMPQ\t.+, [$]251","ADDQ\t[$]-5," + // s390x:"CLGIJ\t[$]4, R[0-9]+, [$]251","ADD\t[$]-5," + for x := <-c; x < 256 && x > 4; x = <-c { + } +} + +func si6c(c <-chan int32) { + // amd64:"CMPL\t.+, [$]255","DECL\t" + // s390x:"CLIJ\t[$]12, R[0-9]+, [$]255","ADDW\t[$]-1," + for x := <-c; x > 0 && x <= 256; x = <-c { + } +} + +func si7c(c <-chan int16) { + // amd64:"CMPW\t.+, [$]60","ADDL\t[$]10," + // s390x:"CLIJ\t[$]12, R[0-9]+, [$]60","ADDW\t[$]10," + for x := <-c; x >= -10 && x <= 50; x = <-c { + } +} + +func si8c(c <-chan int8) { + // amd64:"CMPB\t.+, [$]126","ADDL\t[$]126," + // s390x:"CLIJ\t[$]4, R[0-9]+, [$]126","ADDW\t[$]126," + for x := <-c; x >= -126 && x < 0; x = <-c { + } +} + +// ---------------------------------- // +// signed integer range (disjunction) // +// ---------------------------------- // + +func si1d(c <-chan int64) { + // amd64:"CMPQ\t.+, [$]256" + // s390x:"CLGIJ\t[$]2, R[0-9]+, [$]255" + for x := <-c; x < 0 || x >= 256; x = <-c { + } +} + +func si2d(c <-chan int32) { + // amd64:"CMPL\t.+, [$]256" + // s390x:"CLIJ\t[$]2, R[0-9]+, [$]255" + for x := <-c; x < 0 || x >= 256; x = <-c { + } +} + +func si3d(c <-chan int16) { + // amd64:"CMPW\t.+, [$]256" + // s390x:"CLIJ\t[$]2, R[0-9]+, [$]255" + for x := <-c; x < 0 || x >= 256; x = <-c { + } +} + +func si4d(c <-chan int8) { + // amd64:"CMPB\t.+, [$]10" + // s390x:"CLIJ\t[$]10, R[0-9]+, [$]10" + for x := <-c; x < 0 || x >= 10; x = <-c { + } +} + +func si5d(c <-chan int64) { + // amd64:"CMPQ\t.+, [$]251","ADDQ\t[$]-5," + // s390x:"CLGIJ\t[$]10, R[0-9]+, [$]251","ADD\t[$]-5," + for x := <-c; x >= 256 || x <= 4; x = <-c { + } +} + +func si6d(c <-chan int32) { + // amd64:"CMPL\t.+, [$]255","DECL\t" + // s390x:"CLIJ\t[$]2, R[0-9]+, [$]255","ADDW\t[$]-1," + for x := <-c; x <= 0 || x > 256; x = <-c { + } +} + +func si7d(c <-chan int16) { + // amd64:"CMPW\t.+, [$]60","ADDL\t[$]10," + // s390x:"CLIJ\t[$]2, R[0-9]+, [$]60","ADDW\t[$]10," + for x := <-c; x < -10 || x > 50; x = <-c { + } +} + +func si8d(c <-chan int8) { + // amd64:"CMPB\t.+, [$]126","ADDL\t[$]126," + // s390x:"CLIJ\t[$]10, R[0-9]+, [$]126","ADDW\t[$]126," + for x := <-c; x < -126 || x >= 0; x = <-c { + } +} + +// ------------------------------------ // +// unsigned integer range (conjunction) // +// ------------------------------------ // + +func ui1c(c <-chan uint64) { + // amd64:"CMPQ\t.+, [$]251","ADDQ\t[$]-5," + // s390x:"CLGIJ\t[$]4, R[0-9]+, [$]251","ADD\t[$]-5," + for x := <-c; x < 256 && x > 4; x = <-c { + } +} + +func ui2c(c <-chan uint32) { + // amd64:"CMPL\t.+, [$]255","DECL\t" + // s390x:"CLIJ\t[$]12, R[0-9]+, [$]255","ADDW\t[$]-1," + for x := <-c; x > 0 && x <= 256; x = <-c { + } +} + +func ui3c(c <-chan uint16) { + // amd64:"CMPW\t.+, [$]40","ADDL\t[$]-10," + // s390x:"CLIJ\t[$]12, R[0-9]+, [$]40","ADDW\t[$]-10," + for x := <-c; x >= 10 && x <= 50; x = <-c { + } +} + +func ui4c(c <-chan uint8) { + // amd64:"CMPB\t.+, [$]2","ADDL\t[$]-126," + // s390x:"CLIJ\t[$]4, R[0-9]+, [$]2","ADDW\t[$]-126," + for x := <-c; x >= 126 && x < 128; x = <-c { + } +} + +// ------------------------------------ // +// unsigned integer range (disjunction) // +// ------------------------------------ // + +func ui1d(c <-chan uint64) { + // amd64:"CMPQ\t.+, [$]251","ADDQ\t[$]-5," + // s390x:"CLGIJ\t[$]10, R[0-9]+, [$]251","ADD\t[$]-5," + for x := <-c; x >= 256 || x <= 4; x = <-c { + } +} + +func ui2d(c <-chan uint32) { + // amd64:"CMPL\t.+, [$]254","ADDL\t[$]-2," + // s390x:"CLIJ\t[$]2, R[0-9]+, [$]254","ADDW\t[$]-2," + for x := <-c; x <= 1 || x > 256; x = <-c { + } +} + +func ui3d(c <-chan uint16) { + // amd64:"CMPW\t.+, [$]40","ADDL\t[$]-10," + // s390x:"CLIJ\t[$]2, R[0-9]+, [$]40","ADDW\t[$]-10," + for x := <-c; x < 10 || x > 50; x = <-c { + } +} + +func ui4d(c <-chan uint8) { + // amd64:"CMPB\t.+, [$]2","ADDL\t[$]-126," + // s390x:"CLIJ\t[$]10, R[0-9]+, [$]2","ADDW\t[$]-126," + for x := <-c; x < 126 || x >= 128; x = <-c { + } +} diff --git a/test/codegen/issue33580.go b/test/codegen/issue33580.go new file mode 100644 index 00000000..1ded944c --- /dev/null +++ b/test/codegen/issue33580.go @@ -0,0 +1,25 @@ +// asmcheck + +// 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. + +// Make sure we reuse large constant loads, if we can. +// See issue 33580. + +package codegen + +const ( + A = 7777777777777777 + B = 8888888888888888 +) + +func f(x, y uint64) uint64 { + p := x & A + q := y & A + r := x & B + // amd64:-"MOVQ.*8888888888888888" + s := y & B + + return p * q * r * s +} diff --git a/test/codegen/issue38554.go b/test/codegen/issue38554.go new file mode 100644 index 00000000..84db8473 --- /dev/null +++ b/test/codegen/issue38554.go @@ -0,0 +1,15 @@ +// asmcheck + +// 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. + +// Test that we are zeroing directly instead of +// copying a large zero value. Issue 38554. + +package codegen + +func retlarge() [256]byte { + // amd64:-"DUFFCOPY" + return [256]byte{} +} diff --git a/test/codegen/math.go b/test/codegen/math.go index 597271ce..1ebfda04 100644 --- a/test/codegen/math.go +++ b/test/codegen/math.go @@ -63,6 +63,7 @@ func abs(x, y float64) { // ppc64:"FABS\t" // ppc64le:"FABS\t" // wasm:"F64Abs" + // arm/6:"ABSD\t" sink64[0] = math.Abs(x) // amd64:"BTRQ\t[$]63","PXOR" (TODO: this should be BTSQ) @@ -80,7 +81,7 @@ func abs32(x float32) float32 { // Check that it's using integer registers func copysign(a, b, c float64) { - // amd64:"BTRQ\t[$]63","SHRQ\t[$]63","SHLQ\t[$]63","ORQ" + // amd64:"BTRQ\t[$]63","ANDQ","ORQ" // s390x:"CPSDR",-"MOVD" (no integer load/store) // ppc64:"FCPSGN" // ppc64le:"FCPSGN" @@ -99,13 +100,23 @@ func copysign(a, b, c float64) { // s390x:"LNDFR\t",-"MOVD\t" (no integer load/store) sink64[2] = math.Float64frombits(math.Float64bits(a) | 1<<63) - // amd64:-"SHLQ\t[$]1",-"SHRQ\t[$]1","SHRQ\t[$]63","SHLQ\t[$]63","ORQ" + // amd64:"ANDQ","ORQ" // s390x:"CPSDR\t",-"MOVD\t" (no integer load/store) // ppc64:"FCPSGN" // ppc64le:"FCPSGN" sink64[3] = math.Copysign(-1, c) } +func fma(x, y, z float64) float64 { + // amd64:"VFMADD231SD" + // arm/6:"FMULAD" + // arm64:"FMADDD" + // s390x:"FMADD" + // ppc64:"FMADD" + // ppc64le:"FMADD" + return math.FMA(x, y, z) +} + func fromFloat64(f64 float64) uint64 { // amd64:"MOVQ\tX.*, [^X].*" // arm64:"FMOVD\tF.*, R.*" @@ -140,13 +151,13 @@ func toFloat32(u32 uint32) float32 { func constantCheck64() bool { // amd64:"MOVB\t[$]0",-"FCMP",-"MOVB\t[$]1" // s390x:"MOV(B|BZ|D)\t[$]0,",-"FCMPU",-"MOV(B|BZ|D)\t[$]1," - return 0.5 == float64(uint32(1)) || 1.5 > float64(uint64(1<<63)) || math.NaN() == math.NaN() + return 0.5 == float64(uint32(1)) || 1.5 > float64(uint64(1<<63)) } func constantCheck32() bool { // amd64:"MOVB\t[$]1",-"FCMP",-"MOVB\t[$]0" // s390x:"MOV(B|BZ|D)\t[$]1,",-"FCMPU",-"MOV(B|BZ|D)\t[$]0," - return float32(0.5) <= float32(int64(1)) && float32(1.5) >= float32(int32(-1<<31)) && float32(math.NaN()) != float32(math.NaN()) + return float32(0.5) <= float32(int64(1)) && float32(1.5) >= float32(int32(-1<<31)) } // Test that integer constants are converted to floating point constants @@ -175,3 +186,32 @@ func constantConvertInt32(x uint32) uint32 { } return x } + +func nanGenerate64() float64 { + // Test to make sure we don't generate a NaN while constant propagating. + // See issue 36400. + zero := 0.0 + // amd64:-"DIVSD" + inf := 1 / zero // +inf. We can constant propagate this one. + negone := -1.0 + + // amd64:"DIVSD" + z0 := zero / zero + // amd64:"MULSD" + z1 := zero * inf + // amd64:"SQRTSD" + z2 := math.Sqrt(negone) + return z0 + z1 + z2 +} + +func nanGenerate32() float32 { + zero := float32(0.0) + // amd64:-"DIVSS" + inf := 1 / zero // +inf. We can constant propagate this one. + + // amd64:"DIVSS" + z0 := zero / zero + // amd64:"MULSS" + z1 := zero * inf + return z0 + z1 +} diff --git a/test/codegen/mathbits.go b/test/codegen/mathbits.go index 0d94bd1b..942605de 100644 --- a/test/codegen/mathbits.go +++ b/test/codegen/mathbits.go @@ -110,8 +110,9 @@ func Len8(n uint8) int { // bits.OnesCount // // -------------------- // +// amd64:".*x86HasPOPCNT" func OnesCount(n uint) int { - // amd64:"POPCNTQ",".*x86HasPOPCNT" + // amd64:"POPCNTQ" // arm64:"VCNT","VUADDLV" // s390x:"POPCNT" // ppc64:"POPCNTD" @@ -120,8 +121,9 @@ func OnesCount(n uint) int { return bits.OnesCount(n) } +// amd64:".*x86HasPOPCNT" func OnesCount64(n uint64) int { - // amd64:"POPCNTQ",".*x86HasPOPCNT" + // amd64:"POPCNTQ" // arm64:"VCNT","VUADDLV" // s390x:"POPCNT" // ppc64:"POPCNTD" @@ -130,8 +132,9 @@ func OnesCount64(n uint64) int { return bits.OnesCount64(n) } +// amd64:".*x86HasPOPCNT" func OnesCount32(n uint32) int { - // amd64:"POPCNTL",".*x86HasPOPCNT" + // amd64:"POPCNTL" // arm64:"VCNT","VUADDLV" // s390x:"POPCNT" // ppc64:"POPCNTW" @@ -140,8 +143,9 @@ func OnesCount32(n uint32) int { return bits.OnesCount32(n) } +// amd64:".*x86HasPOPCNT" func OnesCount16(n uint16) int { - // amd64:"POPCNTL",".*x86HasPOPCNT" + // amd64:"POPCNTL" // arm64:"VCNT","VUADDLV" // s390x:"POPCNT" // ppc64:"POPCNTW" @@ -208,10 +212,12 @@ func RotateLeft64(n uint64) uint64 { func RotateLeft32(n uint32) uint32 { // amd64:"ROLL" 386:"ROLL" + // arm:`MOVW\tR[0-9]+@>23` // arm64:"RORW" // ppc64:"ROTLW" // ppc64le:"ROTLW" // s390x:"RLL" + // wasm:"I32Rotl" return bits.RotateLeft32(n, 9) } @@ -231,6 +237,7 @@ func RotateLeftVariable(n uint, m int) uint { // ppc64:"ROTL" // ppc64le:"ROTL" // s390x:"RLLG" + // wasm:"I64Rotl" return bits.RotateLeft(n, m) } @@ -240,15 +247,18 @@ func RotateLeftVariable64(n uint64, m int) uint64 { // ppc64:"ROTL" // ppc64le:"ROTL" // s390x:"RLLG" + // wasm:"I64Rotl" return bits.RotateLeft64(n, m) } func RotateLeftVariable32(n uint32, m int) uint32 { + // arm:`MOVW\tR[0-9]+@>R[0-9]+` // amd64:"ROLL" // arm64:"RORW" // ppc64:"ROTLW" // ppc64le:"ROTLW" // s390x:"RLL" + // wasm:"I32Rotl" return bits.RotateLeft32(n, m) } @@ -296,6 +306,7 @@ func TrailingZeros32(n uint32) int { func TrailingZeros16(n uint16) int { // amd64:"BSFL","BTSL\\t\\$16" + // 386:"BSFL\t" // arm:"ORR\t\\$65536","CLZ",-"MOVHU\tR" // arm64:"ORR\t\\$65536","RBITW","CLZW",-"MOVHU\tR",-"RBIT\t",-"CLZ\t" // s390x:"FLOGR","OR\t\\$65536" @@ -461,6 +472,69 @@ func Add64M(p, q, r *[3]uint64) { r[2], c = bits.Add64(p[2], q[2], c) } +func Add64PanicOnOverflowEQ(a, b uint64) uint64 { + r, c := bits.Add64(a, b, 0) + // s390x:"BRC\t[$]3,",-"ADDE" + if c == 1 { + panic("overflow") + } + return r +} + +func Add64PanicOnOverflowNE(a, b uint64) uint64 { + r, c := bits.Add64(a, b, 0) + // s390x:"BRC\t[$]3,",-"ADDE" + if c != 0 { + panic("overflow") + } + return r +} + +func Add64PanicOnOverflowGT(a, b uint64) uint64 { + r, c := bits.Add64(a, b, 0) + // s390x:"BRC\t[$]3,",-"ADDE" + if c > 0 { + panic("overflow") + } + return r +} + +func Add64MPanicOnOverflowEQ(a, b [2]uint64) [2]uint64 { + var r [2]uint64 + var c uint64 + r[0], c = bits.Add64(a[0], b[0], c) + r[1], c = bits.Add64(a[1], b[1], c) + // s390x:"BRC\t[$]3," + if c == 1 { + panic("overflow") + } + return r +} + +func Add64MPanicOnOverflowNE(a, b [2]uint64) [2]uint64 { + var r [2]uint64 + var c uint64 + r[0], c = bits.Add64(a[0], b[0], c) + r[1], c = bits.Add64(a[1], b[1], c) + // s390x:"BRC\t[$]3," + if c != 0 { + panic("overflow") + } + return r +} + +func Add64MPanicOnOverflowGT(a, b [2]uint64) [2]uint64 { + var r [2]uint64 + var c uint64 + r[0], c = bits.Add64(a[0], b[0], c) + r[1], c = bits.Add64(a[1], b[1], c) + // s390x:"BRC\t[$]3," + if c > 0 { + panic("overflow") + } + return r +} + // --------------- // // bits.Sub* // // --------------- // @@ -541,6 +615,69 @@ func Sub64M(p, q, r *[3]uint64) { r[2], c = bits.Sub64(p[2], q[2], c) } +func Sub64PanicOnOverflowEQ(a, b uint64) uint64 { + r, b := bits.Sub64(a, b, 0) + // s390x:"BRC\t[$]12,",-"ADDE",-"SUBE" + if b == 1 { + panic("overflow") + } + return r +} + +func Sub64PanicOnOverflowNE(a, b uint64) uint64 { + r, b := bits.Sub64(a, b, 0) + // s390x:"BRC\t[$]12,",-"ADDE",-"SUBE" + if b != 0 { + panic("overflow") + } + return r +} + +func Sub64PanicOnOverflowGT(a, b uint64) uint64 { + r, b := bits.Sub64(a, b, 0) + // s390x:"BRC\t[$]12,",-"ADDE",-"SUBE" + if b > 0 { + panic("overflow") + } + return r +} + +func Sub64MPanicOnOverflowEQ(a, b [2]uint64) [2]uint64 { + var r [2]uint64 + var c uint64 + r[0], c = bits.Sub64(a[0], b[0], c) + r[1], c = bits.Sub64(a[1], b[1], c) + // s390x:"BRC\t[$]12," + if c == 1 { + panic("overflow") + } + return r +} + +func Sub64MPanicOnOverflowNE(a, b [2]uint64) [2]uint64 { + var r [2]uint64 + var c uint64 + r[0], c = bits.Sub64(a[0], b[0], c) + r[1], c = bits.Sub64(a[1], b[1], c) + // s390x:"BRC\t[$]12," + if c != 0 { + panic("overflow") + } + return r +} + +func Sub64MPanicOnOverflowGT(a, b [2]uint64) [2]uint64 { + var r [2]uint64 + var c uint64 + r[0], c = bits.Sub64(a[0], b[0], c) + r[1], c = bits.Sub64(a[1], b[1], c) + // s390x:"BRC\t[$]12," + if c > 0 { + panic("overflow") + } + return r +} + // --------------- // // bits.Mul* // // --------------- // @@ -550,6 +687,8 @@ func Mul(x, y uint) (hi, lo uint) { // arm64:"UMULH","MUL" // ppc64:"MULHDU","MULLD" // ppc64le:"MULHDU","MULLD" + // s390x:"MLGR" + // mips64: "MULVU" return bits.Mul(x, y) } @@ -558,6 +697,8 @@ func Mul64(x, y uint64) (hi, lo uint64) { // arm64:"UMULH","MUL" // ppc64:"MULHDU","MULLD" // ppc64le:"MULHDU","MULLD" + // s390x:"MLGR" + // mips64: "MULVU" return bits.Mul64(x, y) } diff --git a/test/codegen/memcombine.go b/test/codegen/memcombine.go index 747e2300..6ad95145 100644 --- a/test/codegen/memcombine.go +++ b/test/codegen/memcombine.go @@ -57,6 +57,7 @@ func load_le16(b []byte) { // amd64:`MOVWLZX\s\(.*\),`,-`MOVB`,-`OR` // ppc64le:`MOVHZ\s`,-`MOVBZ` // arm64:`MOVHU\s\(R[0-9]+\),`,-`MOVB` + // s390x:`MOVHBR\s\(.*\),` sink16 = binary.LittleEndian.Uint16(b) } @@ -64,6 +65,7 @@ func load_le16_idx(b []byte, idx int) { // amd64:`MOVWLZX\s\(.*\),`,-`MOVB`,-`OR` // ppc64le:`MOVHZ\s`,-`MOVBZ` // arm64:`MOVHU\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOVB` + // s390x:`MOVHBR\s\(.*\)\(.*\*1\),` sink16 = binary.LittleEndian.Uint16(b[idx:]) } @@ -103,6 +105,7 @@ func load_be16(b []byte) { // amd64:`ROLW\s\$8`,-`MOVB`,-`OR` // arm64:`REV16W`,`MOVHU\s\(R[0-9]+\),`,-`MOVB` // ppc64le:`MOVHBR` + // s390x:`MOVHZ\s\(.*\),`,-`OR`,-`ORW`,-`SLD`,-`SLW` sink16 = binary.BigEndian.Uint16(b) } @@ -110,6 +113,7 @@ func load_be16_idx(b []byte, idx int) { // amd64:`ROLW\s\$8`,-`MOVB`,-`OR` // arm64:`REV16W`,`MOVHU\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOVB` // ppc64le:`MOVHBR` + // s390x:`MOVHZ\s\(.*\)\(.*\*1\),`,-`OR`,-`ORW`,-`SLD`,-`SLW` sink16 = binary.BigEndian.Uint16(b[idx:]) } @@ -156,14 +160,14 @@ func load_le_byte8_uint64_inv(s []byte) uint64 { func load_be_byte2_uint16(s []byte) uint16 { // arm64:`MOVHU\t\(R[0-9]+\)`,`REV16W`,-`ORR`,-`MOVB` - // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`OR` + // amd64:`MOVWLZX\s\([A-Z]+\)`,`ROLW`,-`MOVB`,-`OR` // ppc64le:`MOVHBR\t\(R[0-9]+\)`,-`MOVBZ` return uint16(s[0])<<8 | uint16(s[1]) } func load_be_byte2_uint16_inv(s []byte) uint16 { // arm64:`MOVHU\t\(R[0-9]+\)`,`REV16W`,-`ORR`,-`MOVB` - // amd64:`MOVWLZX\s\([A-Z]+\)`,-`MOVB`,-`OR` + // amd64:`MOVWLZX\s\([A-Z]+\)`,`ROLW`,-`MOVB`,-`OR` // ppc64le:`MOVHBR\t\(R[0-9]+\)`,-`MOVBZ` return uint16(s[1]) | uint16(s[0])<<8 } @@ -175,7 +179,7 @@ func load_be_byte4_uint32(s []byte) uint32 { func load_be_byte4_uint32_inv(s []byte) uint32 { // arm64:`MOVWU\t\(R[0-9]+\)`,`REVW`,-`ORR`,-`REV16W`,-`MOV[BH]` - // amd64:`MOVL\s\([A-Z]+\)`,-`MOV[BW]`,-`OR` + // amd64:`MOVL\s\([A-Z]+\)`,`BSWAPL`,-`MOV[BW]`,-`OR` return uint32(s[3]) | uint32(s[2])<<8 | uint32(s[1])<<16 | uint32(s[0])<<24 } @@ -187,7 +191,7 @@ func load_be_byte8_uint64(s []byte) uint64 { func load_be_byte8_uint64_inv(s []byte) uint64 { // arm64:`MOVD\t\(R[0-9]+\)`,`REV`,-`ORR`,-`REVW`,-`REV16W`,-`MOV[BHW]` - // amd64:`MOVQ\s\([A-Z]+\),\s[A-Z]+`,-`MOV[BWL]\t[^$]`,-`OR` + // amd64:`MOVQ\s\([A-Z]+\),\s[A-Z]+`,`BSWAPQ`,-`MOV[BWL]\t[^$]`,-`OR` // ppc64le:`MOVDBR\t\(R[0-9]+\)`,-`MOV[BHW]Z` return uint64(s[7]) | uint64(s[6])<<8 | uint64(s[5])<<16 | uint64(s[4])<<24 | uint64(s[3])<<32 | uint64(s[2])<<40 | uint64(s[1])<<48 | uint64(s[0])<<56 } @@ -317,8 +321,8 @@ func fcall_uint32(a, b uint32) (uint32, uint32) { // We want to merge load+op in the first function, but not in the // second. See Issue 19595. func load_op_merge(p, q *int) { - x := *p - *q += x // amd64:`ADDQ\t\(` + x := *p // amd64:`ADDQ\t\(` + *q += x // The combined nilcheck and load would normally have this line number, but we want that combined operation to have the line number of the nil check instead (see #33724). } func load_op_no_merge(p, q *int) { x := *p @@ -351,6 +355,7 @@ func store_le64(b []byte) { // amd64:`MOVQ\s.*\(.*\)$`,-`SHR.` // arm64:`MOVD`,-`MOV[WBH]` // ppc64le:`MOVD\s`,-`MOV[BHW]\s` + // s390x:`MOVDBR\s.*\(.*\)$` binary.LittleEndian.PutUint64(b, sink64) } @@ -358,6 +363,7 @@ func store_le64_idx(b []byte, idx int) { // amd64:`MOVQ\s.*\(.*\)\(.*\*1\)$`,-`SHR.` // arm64:`MOVD\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`,-`MOV[BHW]` // ppc64le:`MOVD\s`,-`MOV[BHW]\s` + // s390x:`MOVDBR\s.*\(.*\)\(.*\*1\)$` binary.LittleEndian.PutUint64(b[idx:], sink64) } @@ -365,6 +371,7 @@ func store_le32(b []byte) { // amd64:`MOVL\s` // arm64:`MOVW`,-`MOV[BH]` // ppc64le:`MOVW\s` + // s390x:`MOVWBR\s.*\(.*\)$` binary.LittleEndian.PutUint32(b, sink32) } @@ -372,6 +379,7 @@ func store_le32_idx(b []byte, idx int) { // amd64:`MOVL\s` // arm64:`MOVW\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`,-`MOV[BH]` // ppc64le:`MOVW\s` + // s390x:`MOVWBR\s.*\(.*\)\(.*\*1\)$` binary.LittleEndian.PutUint32(b[idx:], sink32) } @@ -379,6 +387,7 @@ func store_le16(b []byte) { // amd64:`MOVW\s` // arm64:`MOVH`,-`MOVB` // ppc64le:`MOVH\s` + // s390x:`MOVHBR\s.*\(.*\)$` binary.LittleEndian.PutUint16(b, sink16) } @@ -386,6 +395,7 @@ func store_le16_idx(b []byte, idx int) { // amd64:`MOVW\s` // arm64:`MOVH\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`,-`MOVB` // ppc64le:`MOVH\s` + // s390x:`MOVHBR\s.*\(.*\)\(.*\*1\)$` binary.LittleEndian.PutUint16(b[idx:], sink16) } @@ -393,6 +403,7 @@ func store_be64(b []byte) { // amd64:`BSWAPQ`,-`SHR.` // arm64:`MOVD`,`REV`,-`MOV[WBH]`,-`REVW`,-`REV16W` // ppc64le:`MOVDBR` + // s390x:`MOVD\s.*\(.*\)$`,-`SRW\s`,-`SRD\s` binary.BigEndian.PutUint64(b, sink64) } @@ -400,6 +411,7 @@ func store_be64_idx(b []byte, idx int) { // amd64:`BSWAPQ`,-`SHR.` // arm64:`REV`,`MOVD\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`,-`MOV[BHW]`,-`REV16W`,-`REVW` // ppc64le:`MOVDBR` + // s390x:`MOVD\s.*\(.*\)\(.*\*1\)$`,-`SRW\s`,-`SRD\s` binary.BigEndian.PutUint64(b[idx:], sink64) } @@ -407,6 +419,7 @@ func store_be32(b []byte) { // amd64:`BSWAPL`,-`SHR.` // arm64:`MOVW`,`REVW`,-`MOV[BH]`,-`REV16W` // ppc64le:`MOVWBR` + // s390x:`MOVW\s.*\(.*\)$`,-`SRW\s`,-`SRD\s` binary.BigEndian.PutUint32(b, sink32) } @@ -414,6 +427,7 @@ func store_be32_idx(b []byte, idx int) { // amd64:`BSWAPL`,-`SHR.` // arm64:`REVW`,`MOVW\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`,-`MOV[BH]`,-`REV16W` // ppc64le:`MOVWBR` + // s390x:`MOVW\s.*\(.*\)\(.*\*1\)$`,-`SRW\s`,-`SRD\s` binary.BigEndian.PutUint32(b[idx:], sink32) } @@ -421,6 +435,7 @@ func store_be16(b []byte) { // amd64:`ROLW\s\$8`,-`SHR.` // arm64:`MOVH`,`REV16W`,-`MOVB` // ppc64le:`MOVHBR` + // s390x:`MOVH\s.*\(.*\)$`,-`SRW\s`,-`SRD\s` binary.BigEndian.PutUint16(b, sink16) } @@ -428,6 +443,7 @@ func store_be16_idx(b []byte, idx int) { // amd64:`ROLW\s\$8`,-`SHR.` // arm64:`MOVH\sR[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`,`REV16W`,-`MOVB` // ppc64le:`MOVHBR` + // s390x:`MOVH\s.*\(.*\)\(.*\*1\)$`,-`SRW\s`,-`SRD\s` binary.BigEndian.PutUint16(b[idx:], sink16) } diff --git a/test/codegen/memops.go b/test/codegen/memops.go index dcf58636..cd35910c 100644 --- a/test/codegen/memops.go +++ b/test/codegen/memops.go @@ -93,3 +93,264 @@ func compMem3(x, y *int) (int, bool) { // 386:`CMPL\t\(` return r, r < *y } + +// The following functions test that indexed load/store operations get generated. + +func idxInt8(x, y []int8, i int) { + var t int8 + // amd64: `MOVBL[SZ]X\t1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), [A-Z]+[0-9]*` + // 386: `MOVBL[SZ]X\t1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), [A-Z]+[0-9]*` + t = x[i+1] + // amd64: `MOVB\t[A-Z]+[0-9]*, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + // 386: `MOVB\t[A-Z]+[0-9]*, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + y[i+1] = t + // amd64: `MOVB\t[$]77, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + // 386: `MOVB\t[$]77, 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + x[i+1] = 77 +} + +func idxInt16(x, y []int16, i int) { + var t int16 + // amd64: `MOVWL[SZ]X\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), [A-Z]+[0-9]*` + // 386: `MOVWL[SZ]X\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), [A-Z]+[0-9]*` + t = x[i+1] + // amd64: `MOVW\t[A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + // 386: `MOVW\t[A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + y[i+1] = t + // amd64: `MOVWL[SZ]X\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), [A-Z]+[0-9]*` + // 386: `MOVWL[SZ]X\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), [A-Z]+[0-9]*` + t = x[16*i+1] + // amd64: `MOVW\t[A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)` + // 386: `MOVW\t[A-Z]+[0-9]*, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)` + y[16*i+1] = t + // amd64: `MOVW\t[$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + // 386: `MOVW\t[$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + x[i+1] = 77 + // amd64: `MOVW\t[$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)` + // 386: `MOVW\t[$]77, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\)` + x[16*i+1] = 77 +} + +func idxInt32(x, y []int32, i int) { + var t int32 + // amd64: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` + // 386: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` + t = x[i+1] + // amd64: `MOVL\t[A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + // 386: `MOVL\t[A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + y[i+1] = t + // amd64: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*` + t = x[2*i+1] + // amd64: `MOVL\t[A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + y[2*i+1] = t + // amd64: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), [A-Z]+[0-9]*` + // 386: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), [A-Z]+[0-9]*` + t = x[16*i+1] + // amd64: `MOVL\t[A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` + // 386: `MOVL\t[A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` + y[16*i+1] = t + // amd64: `MOVL\t[$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + // 386: `MOVL\t[$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + x[i+1] = 77 + // amd64: `MOVL\t[$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` + // 386: `MOVL\t[$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` + x[16*i+1] = 77 +} + +func idxInt64(x, y []int64, i int) { + var t int64 + // amd64: `MOVQ\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*` + t = x[i+1] + // amd64: `MOVQ\t[A-Z]+[0-9]*, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + y[i+1] = t + // amd64: `MOVQ\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), [A-Z]+[0-9]*` + t = x[16*i+1] + // amd64: `MOVQ\t[A-Z]+[0-9]*, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\)` + y[16*i+1] = t + // amd64: `MOVQ\t[$]77, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + x[i+1] = 77 + // amd64: `MOVQ\t[$]77, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\)` + x[16*i+1] = 77 +} + +func idxFloat32(x, y []float32, i int) { + var t float32 + // amd64: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+` + // 386/sse2: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), X[0-9]+` + t = x[i+1] + // amd64: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + // 386/sse2: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + y[i+1] = t + // amd64: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), X[0-9]+` + // 386/sse2: `MOVSS\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), X[0-9]+` + t = x[16*i+1] + // amd64: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` + // 386/sse2: `MOVSS\tX[0-9]+, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\)` + y[16*i+1] = t +} + +func idxFloat64(x, y []float64, i int) { + var t float64 + // amd64: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+` + // 386/sse2: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), X[0-9]+` + t = x[i+1] + // amd64: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + // 386/sse2: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + y[i+1] = t + // amd64: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), X[0-9]+` + // 386/sse2: `MOVSD\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), X[0-9]+` + t = x[16*i+1] + // amd64: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\)` + // 386/sse2: `MOVSD\tX[0-9]+, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\)` + y[16*i+1] = t +} + +func idxLoadPlusOp32(x []int32, i int) int32 { + s := x[0] + // 386: `ADDL\t4\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + // amd64: `ADDL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` + s += x[i+1] + // 386: `SUBL\t8\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + // amd64: `SUBL\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` + s -= x[i+2] + // 386: `IMULL\t12\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + s *= x[i+3] + // 386: `ANDL\t16\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + // amd64: `ANDL\t16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` + s &= x[i+4] + // 386: `ORL\t20\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + // amd64: `ORL\t20\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` + s |= x[i+5] + // 386: `XORL\t24\([A-Z]+\)\([A-Z]+\*4\), [A-Z]+` + // amd64: `XORL\t24\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` + s ^= x[i+6] + return s +} + +func idxLoadPlusOp64(x []int64, i int) int64 { + s := x[0] + // amd64: `ADDQ\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*` + s += x[i+1] + // amd64: `SUBQ\t16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*` + s -= x[i+2] + // amd64: `ANDQ\t24\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*` + s &= x[i+3] + // amd64: `ORQ\t32\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*` + s |= x[i+4] + // amd64: `XORQ\t40\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*` + s ^= x[i+5] + return s +} + +func idxStorePlusOp32(x []int32, i int, v int32) { + // 386: `ADDL\t[A-Z]+, 4\([A-Z]+\)\([A-Z]+\*4\)` + // amd64: `ADDL\t[A-Z]+[0-9]*, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + x[i+1] += v + // 386: `SUBL\t[A-Z]+, 8\([A-Z]+\)\([A-Z]+\*4\)` + // amd64: `SUBL\t[A-Z]+[0-9]*, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + x[i+2] -= v + // 386: `ANDL\t[A-Z]+, 12\([A-Z]+\)\([A-Z]+\*4\)` + // amd64: `ANDL\t[A-Z]+[0-9]*, 12\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + x[i+3] &= v + // 386: `ORL\t[A-Z]+, 16\([A-Z]+\)\([A-Z]+\*4\)` + // amd64: `ORL\t[A-Z]+[0-9]*, 16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + x[i+4] |= v + // 386: `XORL\t[A-Z]+, 20\([A-Z]+\)\([A-Z]+\*4\)` + // amd64: `XORL\t[A-Z]+[0-9]*, 20\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + x[i+5] ^= v + + // 386: `ADDL\t[$]77, 24\([A-Z]+\)\([A-Z]+\*4\)` + // amd64: `ADDL\t[$]77, 24\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + x[i+6] += 77 + // 386: `ANDL\t[$]77, 28\([A-Z]+\)\([A-Z]+\*4\)` + // amd64: `ANDL\t[$]77, 28\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + x[i+7] &= 77 + // 386: `ORL\t[$]77, 32\([A-Z]+\)\([A-Z]+\*4\)` + // amd64: `ORL\t[$]77, 32\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + x[i+8] |= 77 + // 386: `XORL\t[$]77, 36\([A-Z]+\)\([A-Z]+\*4\)` + // amd64: `XORL\t[$]77, 36\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\)` + x[i+9] ^= 77 +} + +func idxStorePlusOp64(x []int64, i int, v int64) { + // amd64: `ADDQ\t[A-Z]+[0-9]*, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + x[i+1] += v + // amd64: `SUBQ\t[A-Z]+[0-9]*, 16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + x[i+2] -= v + // amd64: `ANDQ\t[A-Z]+[0-9]*, 24\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + x[i+3] &= v + // amd64: `ORQ\t[A-Z]+[0-9]*, 32\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + x[i+4] |= v + // amd64: `XORQ\t[A-Z]+[0-9]*, 40\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + x[i+5] ^= v + + // amd64: `ADDQ\t[$]77, 48\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + x[i+6] += 77 + // amd64: `ANDQ\t[$]77, 56\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + x[i+7] &= 77 + // amd64: `ORQ\t[$]77, 64\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + x[i+8] |= 77 + // amd64: `XORQ\t[$]77, 72\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\)` + x[i+9] ^= 77 +} + +func idxCompare(i int) int { + // amd64: `MOVBLZX\t1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), [A-Z]+[0-9]*` + if x8[i+1] < x8[0] { + return 0 + } + // amd64: `MOVWLZX\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), [A-Z]+[0-9]*` + if x16[i+1] < x16[0] { + return 0 + } + // amd64: `MOVWLZX\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), [A-Z]+[0-9]*` + if x16[16*i+1] < x16[0] { + return 0 + } + // amd64: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` + if x32[i+1] < x32[0] { + return 0 + } + // amd64: `MOVL\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), [A-Z]+[0-9]*` + if x32[16*i+1] < x32[0] { + return 0 + } + // amd64: `MOVQ\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*` + if x64[i+1] < x64[0] { + return 0 + } + // amd64: `MOVQ\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), [A-Z]+[0-9]*` + if x64[16*i+1] < x64[0] { + return 0 + } + // amd64: `MOVBLZX\t2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\), [A-Z]+[0-9]*` + if x8[i+2] < 77 { + return 0 + } + // amd64: `MOVWLZX\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\), [A-Z]+[0-9]*` + if x16[i+2] < 77 { + return 0 + } + // amd64: `MOVWLZX\t4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[12]\), [A-Z]+[0-9]*` + if x16[16*i+2] < 77 { + return 0 + } + // amd64: `MOVL\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*4\), [A-Z]+[0-9]*` + if x32[i+2] < 77 { + return 0 + } + // amd64: `MOVL\t8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[14]\), [A-Z]+[0-9]*` + if x32[16*i+2] < 77 { + return 0 + } + // amd64: `MOVQ\t16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*8\), [A-Z]+[0-9]*` + if x64[i+2] < 77 { + return 0 + } + // amd64: `MOVQ\t16\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*[18]\), [A-Z]+[0-9]*` + if x64[16*i+2] < 77 { + return 0 + } + return 1 +} diff --git a/test/codegen/retpoline.go b/test/codegen/retpoline.go new file mode 100644 index 00000000..15d6a266 --- /dev/null +++ b/test/codegen/retpoline.go @@ -0,0 +1,14 @@ +// +build amd64 +// asmcheck -gcflags=-spectre=ret + +package codegen + +func CallFunc(f func()) { + // amd64:`CALL\truntime.retpoline` + f() +} + +func CallInterface(x interface{ M() }) { + // amd64:`CALL\truntime.retpoline` + x.M() +} diff --git a/test/codegen/shift.go b/test/codegen/shift.go index 4ae9d7d6..5e50ea6b 100644 --- a/test/codegen/shift.go +++ b/test/codegen/shift.go @@ -12,61 +12,85 @@ package codegen func lshMask64x64(v int64, s uint64) int64 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ANDCC",-"ORN",-"ISEL" + // ppc64:"ANDCC",-"ORN",-"ISEL" return v << (s & 63) } func rshMask64Ux64(v uint64, s uint64) uint64 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ANDCC",-"ORN",-"ISEL" + // ppc64:"ANDCC",-"ORN",-"ISEL" return v >> (s & 63) } func rshMask64x64(v int64, s uint64) int64 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ANDCC",-ORN",-"ISEL" + // ppc64:"ANDCC",-"ORN",-"ISEL" return v >> (s & 63) } func lshMask32x64(v int32, s uint64) int32 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ISEL",-"ORN" + // ppc64:"ISEL",-"ORN" return v << (s & 63) } func rshMask32Ux64(v uint32, s uint64) uint32 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ISEL",-"ORN" + // ppc64:"ISEL",-"ORN" return v >> (s & 63) } func rshMask32x64(v int32, s uint64) int32 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ISEL",-"ORN" + // ppc64:"ISEL",-"ORN" return v >> (s & 63) } func lshMask64x32(v int64, s uint32) int64 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ANDCC",-"ORN" + // ppc64:"ANDCC",-"ORN" return v << (s & 63) } func rshMask64Ux32(v uint64, s uint32) uint64 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ANDCC",-"ORN" + // ppc64:"ANDCC",-"ORN" return v >> (s & 63) } func rshMask64x32(v int64, s uint32) int64 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ANDCC",-"ORN",-"ISEL" + // ppc64:"ANDCC",-"ORN",-"ISEL" return v >> (s & 63) } func lshMask64x32Ext(v int64, s int32) int64 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ANDCC",-"ORN",-"ISEL" + // ppc64:"ANDCC",-"ORN",-"ISEL" return v << uint(s&63) } func rshMask64Ux32Ext(v uint64, s int32) uint64 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ANDCC",-"ORN",-"ISEL" + // ppc64:"ANDCC",-"ORN",-"ISEL" return v >> uint(s&63) } func rshMask64x32Ext(v int64, s int32) int64 { // s390x:-".*AND",-".*MOVDGE" + // ppc64le:"ANDCC",-"ORN",-"ISEL" + // ppc64:"ANDCC",-"ORN",-"ISEL" return v >> uint(s&63) } @@ -102,9 +126,9 @@ func lshSignedMasked(v8 int8, v16 int16, v32 int32, v64 int64, x int) { // bounded shifts // // ------------------ // -func lshGuarded64(v int64, s uint) int64 { +func rshGuarded64(v int64, s uint) int64 { if s < 64 { - // s390x:-".*AND",-".*MOVDGE" + // s390x:-".*AND",-".*MOVDGE" wasm:-"Select",-".*LtU" return v >> s } panic("shift too large") @@ -112,16 +136,39 @@ func lshGuarded64(v int64, s uint) int64 { func rshGuarded64U(v uint64, s uint) uint64 { if s < 64 { - // s390x:-".*AND",-".*MOVDGE" + // s390x:-".*AND",-".*MOVDGE" wasm:-"Select",-".*LtU" return v >> s } panic("shift too large") } -func rshGuarded64(v int64, s uint) int64 { +func lshGuarded64(v int64, s uint) int64 { if s < 64 { - // s390x:-".*AND",-".*MOVDGE" + // s390x:-".*AND",-".*MOVDGE" wasm:-"Select",-".*LtU" return v << s } panic("shift too large") } + +func checkWidenAfterShift(v int64, u uint64) (int64, uint64) { + + // ppc64le:-".*MOVW" + f := int32(v>>32) + // ppc64le:".*MOVW" + f += int32(v>>31) + // ppc64le:-".*MOVH" + g := int16(v>>48) + // ppc64le:".*MOVH" + g += int16(v>>30) + // ppc64le:-".*MOVH" + g += int16(f>>16) + // ppc64le:-".*MOVB" + h := int8(v>>56) + // ppc64le:".*MOVB" + h += int8(v>>28) + // ppc64le:-".*MOVB" + h += int8(f>>24) + // ppc64le:".*MOVB" + h += int8(f>>16) + return int64(h),uint64(g) +} diff --git a/test/codegen/shortcircuit.go b/test/codegen/shortcircuit.go new file mode 100644 index 00000000..e971dca3 --- /dev/null +++ b/test/codegen/shortcircuit.go @@ -0,0 +1,17 @@ +// asmcheck + +// 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 codegen + +func efaceExtract(e interface{}) int { + // This should be compiled with only + // a single conditional jump. + // amd64:-"JMP" + if x, ok := e.(int); ok { + return x + } + return 0 +} diff --git a/test/codegen/slices.go b/test/codegen/slices.go index 6477c6f6..40e857f9 100644 --- a/test/codegen/slices.go +++ b/test/codegen/slices.go @@ -44,6 +44,27 @@ func SliceExtensionConst(s []int) []int { return append(s, make([]int, 1<<2)...) } +func SliceExtensionConstInt64(s []int) []int { + // amd64:`.*runtime\.memclrNoHeapPointers` + // amd64:-`.*runtime\.makeslice` + // amd64:-`.*runtime\.panicmakeslicelen` + return append(s, make([]int, int64(1<<2))...) +} + +func SliceExtensionConstUint64(s []int) []int { + // amd64:`.*runtime\.memclrNoHeapPointers` + // amd64:-`.*runtime\.makeslice` + // amd64:-`.*runtime\.panicmakeslicelen` + return append(s, make([]int, uint64(1<<2))...) +} + +func SliceExtensionConstUint(s []int) []int { + // amd64:`.*runtime\.memclrNoHeapPointers` + // amd64:-`.*runtime\.makeslice` + // amd64:-`.*runtime\.panicmakeslicelen` + return append(s, make([]int, uint(1<<2))...) +} + func SliceExtensionPointer(s []*int, l int) []*int { // amd64:`.*runtime\.memclrHasPointers` // amd64:-`.*runtime\.makeslice` @@ -56,12 +77,216 @@ func SliceExtensionVar(s []byte, l int) []byte { return append(s, make([]byte, l)...) } +func SliceExtensionVarInt64(s []byte, l int64) []byte { + // amd64:`.*runtime\.memclrNoHeapPointers` + // amd64:-`.*runtime\.makeslice` + // amd64:`.*runtime\.panicmakeslicelen` + return append(s, make([]byte, l)...) +} + +func SliceExtensionVarUint64(s []byte, l uint64) []byte { + // amd64:`.*runtime\.memclrNoHeapPointers` + // amd64:-`.*runtime\.makeslice` + // amd64:`.*runtime\.panicmakeslicelen` + return append(s, make([]byte, l)...) +} + +func SliceExtensionVarUint(s []byte, l uint) []byte { + // amd64:`.*runtime\.memclrNoHeapPointers` + // amd64:-`.*runtime\.makeslice` + // amd64:`.*runtime\.panicmakeslicelen` + return append(s, make([]byte, l)...) +} + func SliceExtensionInt64(s []int, l64 int64) []int { // 386:`.*runtime\.makeslice` // 386:-`.*runtime\.memclr` return append(s, make([]int, l64)...) } +// ------------------ // +// Make+Copy // +// ------------------ // + +// Issue #26252 - avoid memclr for make+copy + +func SliceMakeCopyLen(s []int) []int { + // amd64:`.*runtime\.mallocgc` + // amd64:`.*runtime\.memmove` + // amd64:-`.*runtime\.makeslice` + a := make([]int, len(s)) + copy(a, s) + return a +} + +func SliceMakeCopyLenPtr(s []*int) []*int { + // amd64:`.*runtime\.makeslicecopy` + // amd64:-`.*runtime\.makeslice\(` + // amd64:-`.*runtime\.typedslicecopy + a := make([]*int, len(s)) + copy(a, s) + return a +} + +func SliceMakeCopyConst(s []int) []int { + // amd64:`.*runtime\.makeslicecopy` + // amd64:-`.*runtime\.makeslice\(` + // amd64:-`.*runtime\.memmove` + a := make([]int, 4) + copy(a, s) + return a +} + +func SliceMakeCopyConstPtr(s []*int) []*int { + // amd64:`.*runtime\.makeslicecopy` + // amd64:-`.*runtime\.makeslice\(` + // amd64:-`.*runtime\.typedslicecopy + a := make([]*int, 4) + copy(a, s) + return a +} + +func SliceMakeCopyNoOptNoDeref(s []*int) []*int { + a := new([]*int) + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.makeslice\(` + *a = make([]*int, 4) + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.typedslicecopy` + copy(*a, s) + return *a +} + +func SliceMakeCopyNoOptNoVar(s []*int) []*int { + a := make([][]*int, 1) + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.makeslice\(` + a[0] = make([]*int, 4) + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.typedslicecopy` + copy(a[0], s) + return a[0] +} + +func SliceMakeCopyNoOptBlank(s []*int) []*int { + var a []*int + // amd64:-`.*runtime\.makeslicecopy` + _ = make([]*int, 4) + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.typedslicecopy` + copy(a, s) + return a +} + +func SliceMakeCopyNoOptNoMake(s []*int) []*int { + // amd64:-`.*runtime\.makeslicecopy` + // amd64:-`.*runtime\.objectnew` + a := *new([]*int) + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.typedslicecopy` + copy(a, s) + return a +} + +func SliceMakeCopyNoOptNoHeapAlloc(s []*int) int { + // amd64:-`.*runtime\.makeslicecopy` + a := make([]*int, 4) + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.typedslicecopy` + copy(a, s) + return cap(a) +} + +func SliceMakeCopyNoOptNoCap(s []*int) []*int { + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.makeslice\(` + a := make([]*int, 0, 4) + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.typedslicecopy` + copy(a, s) + return a +} + +func SliceMakeCopyNoOptNoCopy(s []*int) []*int { + copy := func(x, y []*int) {} + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.makeslice\(` + a := make([]*int, 4) + // amd64:-`.*runtime\.makeslicecopy` + copy(a, s) + return a +} + +func SliceMakeCopyNoOptWrongOrder(s []*int) []*int { + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.makeslice\(` + a := make([]*int, 4) + // amd64:`.*runtime\.typedslicecopy` + // amd64:-`.*runtime\.makeslicecopy` + copy(s, a) + return a +} + +func SliceMakeCopyNoOptWrongAssign(s []*int) []*int { + var a []*int + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.makeslice\(` + s = make([]*int, 4) + // amd64:`.*runtime\.typedslicecopy` + // amd64:-`.*runtime\.makeslicecopy` + copy(a, s) + return s +} + +func SliceMakeCopyNoOptCopyLength(s []*int) (int, []*int) { + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.makeslice\(` + a := make([]*int, 4) + // amd64:`.*runtime\.typedslicecopy` + // amd64:-`.*runtime\.makeslicecopy` + n := copy(a, s) + return n, a +} + +func SliceMakeCopyNoOptSelfCopy(s []*int) []*int { + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.makeslice\(` + a := make([]*int, 4) + // amd64:`.*runtime\.typedslicecopy` + // amd64:-`.*runtime\.makeslicecopy` + copy(a, a) + return a +} + +func SliceMakeCopyNoOptTargetReference(s []*int) []*int { + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.makeslice\(` + a := make([]*int, 4) + // amd64:`.*runtime\.typedslicecopy` + // amd64:-`.*runtime\.makeslicecopy` + copy(a, s[:len(a)]) + return a +} + +func SliceMakeCopyNoOptCap(s []int) []int { + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.makeslice\(` + a := make([]int, len(s), 9) + // amd64:-`.*runtime\.makeslicecopy` + // amd64:`.*runtime\.memmove` + copy(a, s) + return a +} + +func SliceMakeCopyNoMemmoveDifferentLen(s []int) []int { + // amd64:`.*runtime\.makeslicecopy` + // amd64:-`.*runtime\.memmove` + a := make([]int, len(s)-1) + // amd64:-`.*runtime\.memmove` + copy(a, s) + return a +} + // ---------------------- // // Nil check of &s[0] // // ---------------------- // @@ -71,3 +296,54 @@ func SliceNilCheck(s []int) { // amd64:-`TESTB` _ = *p } + +// ---------------------- // +// Init slice literal // +// ---------------------- // +// See issue 21561 +func InitSmallSliceLiteral() []int { + // amd64:`MOVQ\t[$]42` + return []int{42} +} + +func InitNotSmallSliceLiteral() []int { + // amd64:`MOVQ\t.*autotmp_` + return []int{ + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + 42, + } +} diff --git a/test/codegen/smallintiface.go b/test/codegen/smallintiface.go new file mode 100644 index 00000000..0207a0af --- /dev/null +++ b/test/codegen/smallintiface.go @@ -0,0 +1,22 @@ +// asmcheck + +package codegen + +// 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. + +func booliface() interface{} { + // amd64:`LEAQ\truntime.staticuint64s\+8\(SB\)` + return true +} + +func smallint8iface() interface{} { + // amd64:`LEAQ\truntime.staticuint64s\+2024\(SB\)` + return int8(-3) +} + +func smalluint8iface() interface{} { + // amd64:`LEAQ\truntime.staticuint64s\+24\(SB\)` + return uint8(3) +} diff --git a/test/codegen/spectre.go b/test/codegen/spectre.go new file mode 100644 index 00000000..3753498d --- /dev/null +++ b/test/codegen/spectre.go @@ -0,0 +1,38 @@ +// +build amd64 +// asmcheck -gcflags=-spectre=index + +// 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 codegen + +func IndexArray(x *[10]int, i int) int { + // amd64:`CMOVQCC` + return x[i] +} + +func IndexString(x string, i int) byte { + // amd64:`CMOVQCC` + return x[i] +} + +func IndexSlice(x []float64, i int) float64 { + // amd64:`CMOVQCC` + return x[i] +} + +func SliceArray(x *[10]int, i, j int) []int { + // amd64:`CMOVQHI` + return x[i:j] +} + +func SliceString(x string, i, j int) string { + // amd64:`CMOVQHI` + return x[i:j] +} + +func SliceSlice(x []float64, i, j int) []float64 { + // amd64:`CMOVQHI` + return x[i:j] +} diff --git a/test/codegen/stack.go b/test/codegen/stack.go index 37d378aa..7d70024c 100644 --- a/test/codegen/stack.go +++ b/test/codegen/stack.go @@ -110,7 +110,11 @@ func MightPanic(a []int, i, j, k, s int) { _ = i / j // panicDivide } +// Put a defer in a loop, so second defer is not open-coded func Defer() { + for i := 0; i < 2; i++ { + defer func() {}() + } // amd64:`CALL\truntime\.deferprocStack` defer func() {}() } diff --git a/test/codegen/strings.go b/test/codegen/strings.go index d688b6cb..0859e241 100644 --- a/test/codegen/strings.go +++ b/test/codegen/strings.go @@ -29,6 +29,7 @@ func ConstantLoad() { // 386:`MOVW\t\$12592, \(`,`MOVB\t\$50, 2\(` // arm:`MOVW\t\$48`,`MOVW\t\$49`,`MOVW\t\$50` // arm64:`MOVD\t\$12592`,`MOVD\t\$50` + // wasm:`I64Const\t\$12592`,`I64Store16\t\$0`,`I64Const\t\$50`,`I64Store8\t\$2` bsink = []byte("012") // 858927408 = 0x33323130 @@ -36,6 +37,7 @@ func ConstantLoad() { // amd64:`MOVL\t\$858927408`,`MOVW\t\$13620, 4\(` // 386:`MOVL\t\$858927408`,`MOVW\t\$13620, 4\(` // arm64:`MOVD\t\$858927408`,`MOVD\t\$13620` + // wasm:`I64Const\t\$858927408`,`I64Store32\t\$0`,`I64Const\t\$13620`,`I64Store16\t\$4` bsink = []byte("012345") // 3978425819141910832 = 0x3736353433323130 @@ -43,6 +45,7 @@ func ConstantLoad() { // amd64:`MOVQ\t\$3978425819141910832`,`MOVQ\t\$7306073769690871863` // 386:`MOVL\t\$858927408, \(`,`DUFFCOPY` // arm64:`MOVD\t\$3978425819141910832`,`MOVD\t\$1650538808`,`MOVD\t\$25699`,`MOVD\t\$101` + // wasm:`I64Const\t\$3978425819141910832`,`I64Store\t\$0`,`I64Const\t\$7306073769690871863`,`I64Store\t\$7` bsink = []byte("0123456789abcde") // 56 = 0x38 diff --git a/test/codegen/structs.go b/test/codegen/structs.go index b81ad67c..9eddc5b1 100644 --- a/test/codegen/structs.go +++ b/test/codegen/structs.go @@ -28,7 +28,7 @@ type Z2 struct { func Zero2(t *Z2) { // amd64:`XORPS\tX., X`,`MOVUPS\tX., \(.*\)`,`MOVQ\t\$0, 16\(.*\)` - // amd64:`.*runtime[.]gcWriteBarrier\(SB\)` + // amd64:`.*runtime[.]gcWriteBarrier.*\(SB\)` *t = Z2{} } diff --git a/test/codegen/switch.go b/test/codegen/switch.go new file mode 100644 index 00000000..2ac817d1 --- /dev/null +++ b/test/codegen/switch.go @@ -0,0 +1,22 @@ +// asmcheck + +// 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. + +// These tests check code generation of switch statements. + +package codegen + +// see issue 33934 +func f(x string) int { + // amd64:-`cmpstring` + switch x { + case "": + return -1 + case "1", "2", "3": + return -2 + default: + return -3 + } +} diff --git a/test/complit1.go b/test/complit1.go index 83695a9e..eb0f920f 100644 --- a/test/complit1.go +++ b/test/complit1.go @@ -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 pointer type" - _ = &Ti{} // ERROR "invalid pointer type" + _ = TP{i: 0, f: 0, s: "", next: {}} // ERROR "invalid composite literal type TP" + _ = &Ti{} // ERROR "invalid composite literal type Ti" ) type M map[T]T diff --git a/test/const.go b/test/const.go index f8e0a753..f8aa1dd9 100644 --- a/test/const.go +++ b/test/const.go @@ -24,6 +24,10 @@ const ( ctrue = true cfalse = !ctrue + + // Issue #34563 + _ = string(int(123)) + _ = string(rune(456)) ) const ( @@ -157,10 +161,49 @@ func interfaces() { "for interface{}==int comipiler == runtime") } +// Test that typed floating-point and complex arithmetic +// is computed with correct precision. +func truncate() { + const ( + x30 = 1 << 30 + x60 = 1 << 60 + + staticF32 = float32(x30) + 1 - x30 + staticF64 = float64(x60) + 1 - x60 + staticC64 = complex64(x30) + 1 - x30 + staticC128 = complex128(x60) + 1 - x60 + ) + dynamicF32 := float32(x30) + dynamicF32 += 1 + dynamicF32 -= x30 + + dynamicF64 := float64(x60) + dynamicF64 += 1 + dynamicF64 -= x60 + + dynamicC64 := complex64(x30) + dynamicC64 += 1 + dynamicC64 -= x30 + + dynamicC128 := complex128(x60) + dynamicC128 += 1 + dynamicC128 -= x60 + + assert(staticF32 == 0, "staticF32 == 0") + assert(staticF64 == 0, "staticF64 == 0") + assert(dynamicF32 == 0, "dynamicF32 == 0") + assert(dynamicF64 == 0, "dynamicF64 == 0") + assert(staticC64 == 0, "staticC64 == 0") + assert(staticC128 == 0, "staticC128 == 0") + assert(dynamicC64 == 0, "dynamicC64 == 0") + assert(dynamicC128 == 0, "dynamicC128 == 0") +} + func main() { ints() floats() interfaces() + truncate() assert(ctrue == true, "ctrue == true") assert(cfalse == false, "cfalse == false") diff --git a/test/convlit.go b/test/convlit.go index 904e1e63..de760542 100644 --- a/test/convlit.go +++ b/test/convlit.go @@ -28,8 +28,8 @@ var _ = int(unsafe.Pointer(uintptr(65))) // ERROR "convert" // implicit conversions merit scrutiny var s string var bad1 string = 1 // ERROR "conver|incompatible|invalid|cannot" -var bad2 = s + 1 // ERROR "conver|incompatible|invalid" -var bad3 = s + 'a' // ERROR "conver|incompatible|invalid" +var bad2 = s + 1 // ERROR "conver|incompatible|invalid|cannot" +var bad3 = s + 'a' // ERROR "conver|incompatible|invalid|cannot" var bad4 = "a" + 1 // ERROR "literals|incompatible|convert|invalid" var bad5 = "a" + 'a' // ERROR "literals|incompatible|convert|invalid" diff --git a/test/ddd1.go b/test/ddd1.go index b4ad80b6..b582f221 100644 --- a/test/ddd1.go +++ b/test/ddd1.go @@ -18,7 +18,7 @@ var ( _ = sum() _ = sum(1.0, 2.0) _ = sum(1.5) // ERROR "integer" - _ = sum("hello") // ERROR ".hello. .type string. as type int|incompatible" + _ = sum("hello") // ERROR ".hello. .type untyped string. as type int|incompatible" _ = sum([]int{1}) // ERROR "\[\]int literal.*as type int|incompatible" ) diff --git a/test/defererrcheck.go b/test/defererrcheck.go new file mode 100644 index 00000000..95b91da5 --- /dev/null +++ b/test/defererrcheck.go @@ -0,0 +1,86 @@ +// errorcheck -0 -l -d=defer + +// 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. + +// check that open-coded defers are used in expected situations + +package main + +import "fmt" + +var glob = 3 + +func f1() { + + for i := 0; i < 10; i++ { + fmt.Println("loop") + } + defer func() { // ERROR "open-coded defer" + fmt.Println("defer") + }() +} + +func f2() { + for { + defer func() { // ERROR "heap-allocated defer" + fmt.Println("defer1") + }() + if glob > 2 { + break + } + } + defer func() { // ERROR "stack-allocated defer" + fmt.Println("defer2") + }() +} + +func f3() { + defer func() { // ERROR "stack-allocated defer" + fmt.Println("defer2") + }() + for { + defer func() { // ERROR "heap-allocated defer" + fmt.Println("defer1") + }() + if glob > 2 { + break + } + } +} + +func f4() { + defer func() { // ERROR "open-coded defer" + fmt.Println("defer") + }() +label: + fmt.Println("goto loop") + if glob > 2 { + goto label + } +} + +func f5() { +label: + fmt.Println("goto loop") + defer func() { // ERROR "heap-allocated defer" + fmt.Println("defer") + }() + if glob > 2 { + goto label + } +} + +func f6() { +label: + fmt.Println("goto loop") + if glob > 2 { + goto label + } + // The current analysis doesn't end a backward goto loop, so this defer is + // considered to be inside a loop + defer func() { // ERROR "heap-allocated defer" + fmt.Println("defer") + }() +} diff --git a/test/defernil.go b/test/defernil.go new file mode 100644 index 00000000..5be3abd2 --- /dev/null +++ b/test/defernil.go @@ -0,0 +1,33 @@ +// run + +// 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. + +// Check that deferring a nil function causes a proper +// panic when the deferred function is invoked (not +// when the function is deferred). +// See Issue #8047 and #34926. + +package main + +var x = 0 + +func main() { + defer func() { + err := recover() + if err == nil { + panic("did not panic") + } + if x != 1 { + panic("FAIL") + } + }() + f() +} + +func f() { + var nilf func() + defer nilf() + x = 1 +} diff --git a/test/devirt.go b/test/devirt.go index 23577098..e0149d82 100644 --- a/test/devirt.go +++ b/test/devirt.go @@ -1,4 +1,4 @@ -// errorcheck -0 -d=ssa/opt/debug=3 +// errorcheck -0 -d=ssa/opt/debug=1 package main diff --git a/test/directive.go b/test/directive.go new file mode 100644 index 00000000..6167cd62 --- /dev/null +++ b/test/directive.go @@ -0,0 +1,95 @@ +// 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. + +// Verify that misplaced directives are diagnosed. + +//go:noinline // ERROR "misplaced compiler directive" + +//go:noinline // ERROR "misplaced compiler directive" +package main + +//go:nosplit +func f1() {} + +//go:nosplit +//go:noinline +func f2() {} + +//go:noinline // ERROR "misplaced compiler directive" + +//go:noinline // ERROR "misplaced compiler directive" +var x int + +//go:noinline // ERROR "misplaced compiler directive" +const c = 1 + +//go:noinline // ERROR "misplaced compiler directive" +type T int + +// ok +//go:notinheap +type T1 int + +//go:notinheap // ERROR "misplaced compiler directive" +type ( + //go:notinheap + //go:noinline // ERROR "misplaced compiler directive" + T2 int //go:notinheap // ERROR "misplaced compiler directive" + T2b int + //go:notinheap + T2c int + //go:noinline // ERROR "misplaced compiler directive" + T3 int +) + +//go:notinheap // ERROR "misplaced compiler directive" +type ( + //go:notinheap + T4 int +) + +//go:notinheap // ERROR "misplaced compiler directive" +type () + +type T5 int + +func g() {} //go:noinline // ERROR "misplaced compiler directive" + +// ok: attached to f (duplicated yes, but ok) +//go:noinline + +//go:noinline +func f() { + //go:noinline // ERROR "misplaced compiler directive" + x := 1 + + //go:noinline // ERROR "misplaced compiler directive" + { + _ = x //go:noinline // ERROR "misplaced compiler directive" + } + //go:noinline // ERROR "misplaced compiler directive" + var y int //go:noinline // ERROR "misplaced compiler directive" + //go:noinline // ERROR "misplaced compiler directive" + _ = y + + //go:noinline // ERROR "misplaced compiler directive" + const c = 1 + + //go:noinline // ERROR "misplaced compiler directive" + _ = func() {} + + //go:noinline // ERROR "misplaced compiler directive" + // ok: + //go:notinheap + type T int +} + +// someday there might be a directive that can apply to type aliases, but go:notinheap doesn't. +//go:notinheap // ERROR "misplaced compiler directive" +type T6 = int + +// EOF +//go:noinline // ERROR "misplaced compiler directive" diff --git a/test/escape2.go b/test/escape2.go index f682621c..cf24f4be 100644 --- a/test/escape2.go +++ b/test/escape2.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l -newescape=true +// errorcheck -0 -m -l // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -37,24 +37,24 @@ func foo3b(t T) { // ERROR "leaking param: t$" } // xx isn't going anywhere, so use of yy is ok -func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$" +func foo4(xx, yy *int) { // ERROR "xx does not escape$" "yy does not escape$" xx = yy } // xx isn't going anywhere, so taking address of yy is ok -func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$" +func foo5(xx **int, yy *int) { // ERROR "xx does not escape$" "yy does not escape$" xx = &yy } -func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$" +func foo6(xx **int, yy *int) { // ERROR "xx does not escape$" "leaking param: yy$" *xx = yy } -func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$" +func foo7(xx **int, yy *int) { // ERROR "xx does not escape$" "yy does not escape$" **xx = *yy } -func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$" +func foo8(xx, yy *int) int { // ERROR "xx does not escape$" "yy does not escape$" xx = yy return *xx } @@ -64,7 +64,7 @@ func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$ return xx } -func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$" +func foo10(xx, yy *int) { // ERROR "xx does not escape$" "yy does not escape$" *xx = *yy } @@ -88,7 +88,7 @@ func foo13(yyy **int) { // ERROR "leaking param content: yyy$" *xxx = *yyy } -func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$" +func foo14(yyy **int) { // ERROR "yyy does not escape$" **xxx = **yyy } @@ -100,7 +100,7 @@ func foo16(yy *int) { // ERROR "leaking param: yy$" *xxx = yy } -func foo17(yy *int) { // ERROR "foo17 yy does not escape$" +func foo17(yy *int) { // ERROR "yy does not escape$" **xxx = *yy } @@ -125,11 +125,11 @@ func NewBarp(x *int) *Bar { // ERROR "leaking param: x$" return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" } -func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$" +func NewBarp2(x *int) *Bar { // ERROR "x does not escape$" return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$" } -func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$" +func (b *Bar) NoLeak() int { // ERROR "b does not escape$" return *(b.ii) } @@ -146,18 +146,18 @@ func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$ } func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$" - v := 0 // ERROR "moved to heap: v$" + v := 0 // ERROR "moved to heap: v$" b.ii = &v return b.ii } func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$" - v := 0 // ERROR "moved to heap: v$" + v := 0 // ERROR "moved to heap: v$" b.ii = &v return b.ii } -func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$" +func (b Bar) StillNoLeak() int { // ERROR "b does not escape$" v := 0 b.ii = &v return b.i @@ -176,7 +176,7 @@ func NewBar2() *Bar2 { return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$" } -func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$" +func (b *Bar2) NoLeak() int { // ERROR "b does not escape$" return b.i[0] } @@ -188,7 +188,7 @@ func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 lev return b.ii[0:1] } -func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$" +func (b Bar2) AgainNoLeak() [12]int { // ERROR "b does not escape$" return b.i } @@ -219,7 +219,7 @@ func foo21a() func() int { func foo22() int { x := 42 - return func() int { // ERROR "foo22 func literal does not escape$" + return func() int { // ERROR "func literal does not escape$" return x }() } @@ -250,7 +250,7 @@ func foo23c(x int) func() int { // ERROR "moved to heap: x$" } func foo24(x int) int { - return func() int { // ERROR "foo24 func literal does not escape$" + return func() int { // ERROR "func literal does not escape$" return x }() } @@ -262,7 +262,7 @@ func fooleak(xx *int) int { // ERROR "leaking param: xx$" return *x } -func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$" +func foonoleak(xx *int) int { // ERROR "xx does not escape$" return *x + *xx } @@ -286,7 +286,7 @@ func (f *Foo) fooleak() { // ERROR "leaking param: f$" pf = f } -func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$" +func (f *Foo) foonoleak() { // ERROR "f does not escape$" F.x = f.x } @@ -294,7 +294,7 @@ func (f *Foo) Leak() { // ERROR "leaking param: f$" f.fooleak() } -func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$" +func (f *Foo) NoLeak() { // ERROR "f does not escape$" f.foonoleak() } @@ -302,11 +302,11 @@ func foo41(x int) { // ERROR "moved to heap: x$" F.xx = &x } -func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$" +func (f *Foo) foo42(x int) { // ERROR "f does not escape$" "moved to heap: x$" f.xx = &x } -func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$" +func foo43(f *Foo, x int) { // ERROR "f does not escape$" "moved to heap: x$" f.xx = &x } @@ -314,7 +314,7 @@ func foo44(yy *int) { // ERROR "leaking param: yy$" F.xx = yy } -func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$" +func (f *Foo) foo45() { // ERROR "f does not escape$" F.x = f.x } @@ -407,7 +407,7 @@ func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" return a[1] } -func foo60a(i *int) *int { // ERROR "foo60a i does not escape$" +func foo60a(i *int) *int { // ERROR "i does not escape$" var a [12]*int a[0] = i return nil @@ -423,7 +423,7 @@ func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" return s.b } -func foo61a(i *int) *int { // ERROR "foo61a i does not escape$" +func foo61a(i *int) *int { // ERROR "i does not escape$" type S struct { a, b *int } @@ -439,7 +439,7 @@ func foo62(i *int) *int { // ERROR "leaking param: i$" type S struct { a, b *int } - s := new(S) // ERROR "foo62 new\(S\) does not escape$" + s := new(S) // ERROR "new\(S\) does not escape$" s.a = i return nil // s.b } @@ -448,7 +448,7 @@ type M interface { M() } -func foo63(m M) { // ERROR "foo63 m does not escape$" +func foo63(m M) { // ERROR "m does not escape$" } func foo64(m M) { // ERROR "leaking param: m$" @@ -465,17 +465,17 @@ func (MV) M() {} func foo65() { var mv MV - foo63(&mv) // ERROR "foo65 &mv does not escape$" + foo63(&mv) } func foo66() { - var mv MV // ERROR "moved to heap: mv$" - foo64(&mv) // ERROR "&mv escapes to heap$" + var mv MV // ERROR "moved to heap: mv$" + foo64(&mv) } func foo67() { var mv MV - foo63(mv) // ERROR "foo67 mv does not escape$" + foo63(mv) // ERROR "mv does not escape$" } func foo68() { @@ -489,7 +489,7 @@ func foo69(m M) { // ERROR "leaking param: m$" } func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$" - m = mv1 // ERROR "mv1 escapes to heap$" + m = mv1 foo64(m) } @@ -522,7 +522,7 @@ func foo72a() { var y [10]*int for i := 0; i < 10; i++ { // escapes its scope - x := i // ERROR "moved to heap: x$" + x := i // ERROR "moved to heap: x$" y[i] = &x } return @@ -531,7 +531,7 @@ func foo72a() { func foo72b() [10]*int { var y [10]*int for i := 0; i < 10; i++ { - x := i // ERROR "moved to heap: x$" + x := i // ERROR "moved to heap: x$" y[i] = &x } return y @@ -539,7 +539,7 @@ func foo72b() [10]*int { // issue 2145 func foo73() { - s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal 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 "foo731 \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal 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 "foo74 \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal 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 "foo74a \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal 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 "foo74b \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal 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 "foo74c \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" for i, v := range s { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope @@ -611,57 +611,57 @@ func foo74c() { } } -func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$" +func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "x does not escape$" return y } -func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$" +func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "y does not escape$" return &x[0] } -func foo75(z *int) { // ERROR "foo75 z does not escape$" - myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75 ... argument does not escape$" +func foo75(z *int) { // ERROR "z does not escape$" + myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } -func foo75a(z *int) { // ERROR "foo75a z does not escape$" - myprint1(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75a ... argument does not escape$" +func foo75a(z *int) { // ERROR "z does not escape$" + myprint1(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } func foo75esc(z *int) { // ERROR "leaking param: z$" - gxx = myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75esc ... argument does not escape$" + gxx = myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } -func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$" +func foo75aesc(z *int) { // ERROR "z does not escape$" var ppi **interface{} // assignments to pointer dereferences lose track *ppi = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" } -func foo75aesc1(z *int) { // ERROR "foo75aesc1 z does not escape$" - sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$" +func foo75aesc1(z *int) { // ERROR "z does not escape$" + sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" } func foo76(z *int) { // ERROR "z does not escape" - myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z does not escape" + myprint(nil, z) // ERROR "... argument does not escape$" } func foo76a(z *int) { // ERROR "z does not escape" - myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z does not escape" + myprint1(nil, z) // ERROR "... argument does not escape$" } func foo76b() { - myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76b ... argument does not escape$" + myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } func foo76c() { - myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76c ... argument does not escape$" + myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } func foo76d() { - defer myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76d ... argument does not escape$" + defer myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } func foo76e() { - defer myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76e ... argument does not escape$" + defer myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } func foo76f() { @@ -677,11 +677,11 @@ func foo76g() { } } -func foo77(z []interface{}) { // ERROR "foo77 z does not escape$" +func foo77(z []interface{}) { // ERROR "z does not escape$" myprint(nil, z...) // z does not escape } -func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$" +func foo77a(z []interface{}) { // ERROR "z does not escape$" myprint1(nil, z...) } @@ -691,15 +691,15 @@ func foo77b(z []interface{}) { // ERROR "leaking param: z$" } func foo77c(z []interface{}) { // ERROR "leaking param: z$" - sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$" + sink = myprint1(nil, z...) } func dotdotdot() { i := 0 - myprint(nil, &i) // ERROR "&i does not escape" "dotdotdot ... argument does not escape$" + myprint(nil, &i) // ERROR "... argument does not escape$" j := 0 - myprint1(nil, &j) // ERROR "&j does not escape" "dotdotdot ... argument does not escape$" + myprint1(nil, &j) // ERROR "... argument does not escape$" } func foo78(z int) *int { // ERROR "moved to heap: z$" @@ -728,7 +728,7 @@ func foo80() *int { func foo81() *int { for { - z := new(int) // ERROR "foo81 new\(int\) does not escape$" + z := new(int) // ERROR "new\(int\) does not escape$" _ = z } return nil @@ -736,14 +736,14 @@ func foo81() *int { func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$" -func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$" +func noop(x, y *int) {} // ERROR "x does not escape$" "y does not escape$" func foo82() { - var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" + var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" go noop(tee(&z)) go noop(&x, &y) for { - var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" + var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" defer noop(tee(&u)) defer noop(&v, &w) } @@ -775,7 +775,7 @@ func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" } // does not leak c -func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$" +func foo93(c chan *int) *int { // ERROR "c does not escape$" for v := range c { return v } @@ -794,7 +794,7 @@ func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result } // does leak x -func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$" +func foo95(m map[*int]*int, x *int) { // ERROR "m does not escape$" "leaking param: x$" m[x] = x } @@ -809,7 +809,7 @@ func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" } // does not leak m -func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$" +func foo98(m map[int]*int) *int { // ERROR "m does not escape$" return m[0] } @@ -835,7 +835,7 @@ func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" } // does not leak m -func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" +func foo101a(m [1]*int) *int { // ERROR "m does not escape$" for i := range m { // ERROR "moved to heap: i$" return &i } @@ -843,12 +843,12 @@ func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" } // does leak x -func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$" +func foo102(m []*int, x *int) { // ERROR "m does not escape$" "leaking param: x$" m[0] = x } // does not leak x -func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$" +func foo103(m [1]*int, x *int) { // ERROR "m does not escape$" "x does not escape$" m[0] = x } @@ -878,7 +878,7 @@ func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$" } func foo109(x *int) *int { // ERROR "leaking param: x$" - m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$" + m := map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal 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 "foo110 map\[\*int\]\*int literal does not escape$" + m := map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal does not escape$" return m[nil] } func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" - m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$" + m := []*int{x} // ERROR "\[\]\*int literal 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 "foo114 &Bar literal does not escape$" + m := &Bar{ii: x} // ERROR "&Bar literal does not escape$" return m.ii } @@ -916,22 +916,22 @@ func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" func foo116(b bool) *int { if b { - x := 1 // ERROR "moved to heap: x$" + x := 1 // ERROR "moved to heap: x$" return &x } else { - y := 1 // ERROR "moved to heap: y$" + y := 1 // ERROR "moved to heap: y$" return &y } return nil } -func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$" - x := 1 // ERROR "moved to heap: x$" - unknown(&x) // ERROR "&x escapes to heap$" +func foo117(unknown func(interface{})) { // ERROR "unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" + unknown(&x) } -func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$" - x := 1 // ERROR "moved to heap: x$" +func foo118(unknown func(*int)) { // ERROR "unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" unknown(&x) } @@ -1167,7 +1167,7 @@ func foo122() { goto L1 L1: - i = new(int) // ERROR "foo122 new\(int\) does not escape$" + i = new(int) // ERROR "new\(int\) does not escape$" _ = i } @@ -1182,18 +1182,18 @@ L1: _ = i } -func foo124(x **int) { // ERROR "foo124 x does not escape$" +func foo124(x **int) { // ERROR "x does not escape$" var i int // ERROR "moved to heap: i$" p := &i - func() { // ERROR "foo124 func literal does not escape$" + func() { // ERROR "func literal does not escape$" *x = p }() } -func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$" +func foo125(ch chan *int) { // ERROR "ch does not escape$" var i int // ERROR "moved to heap: i$" p := &i - func() { // ERROR "foo125 func literal does not escape$" + func() { // ERROR "func literal does not escape$" ch <- p }() } @@ -1203,7 +1203,7 @@ func foo126() { for { // loopdepth 1 var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo126 func literal does not escape$" + func() { // ERROR "func literal does not escape$" px = &i }() } @@ -1229,9 +1229,9 @@ func foo128() { func foo129() { var i int // ERROR "moved to heap: i$" p := &i - func() { // ERROR "foo129 func literal does not escape$" + func() { // ERROR "func literal does not escape$" q := p - func() { // ERROR "foo129.func1 func literal does not escape$" + func() { // ERROR "func literal does not escape$" r := q px = r }() @@ -1241,7 +1241,7 @@ func foo129() { func foo130() { for { var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo130 func literal does not escape$" + func() { // ERROR "func literal does not escape$" px = &i }() } @@ -1249,7 +1249,7 @@ func foo130() { func foo131() { var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo131 func literal does not escape$" + func() { // ERROR "func literal does not escape$" px = &i }() } @@ -1263,7 +1263,7 @@ func foo132() { func foo133() { var i int // ERROR "moved to heap: i$" - defer func() { // ERROR "foo133 func literal does not escape$" + defer func() { // ERROR "func literal does not escape$" px = &i }() } @@ -1271,9 +1271,9 @@ func foo133() { func foo134() { var i int p := &i - func() { // ERROR "foo134 func literal does not escape$" + func() { // ERROR "func literal does not escape$" q := p - func() { // ERROR "foo134.func1 func literal does not escape$" + func() { // ERROR "func literal does not escape$" r := q _ = r }() @@ -1281,11 +1281,11 @@ func foo134() { } func foo135() { - var i int // ERROR "moved to heap: i$" + var i int // ERROR "moved to heap: i$" p := &i go func() { // ERROR "func literal escapes to heap$" q := p - func() { // ERROR "foo135.func1 func literal does not escape$" + func() { // ERROR "func literal does not escape$" r := q _ = r }() @@ -1293,11 +1293,11 @@ func foo135() { } func foo136() { - var i int // ERROR "moved to heap: i$" + var i int // ERROR "moved to heap: i$" p := &i go func() { // ERROR "func literal escapes to heap$" q := p - func() { // ERROR "foo136.func1 func literal does not escape$" + func() { // ERROR "func literal does not escape$" r := q px = r }() @@ -1307,7 +1307,7 @@ func foo136() { func foo137() { var i int // ERROR "moved to heap: i$" p := &i - func() { // ERROR "foo137 func literal does not escape$" + func() { // ERROR "func literal does not escape$" q := p go func() { // ERROR "func literal escapes to heap$" r := q @@ -1320,7 +1320,7 @@ func foo138() *byte { type T struct { x [1]byte } - t := new(T) // ERROR "new\(T\) escapes to heap$" + t := new(T) // ERROR "new\(T\) escapes to heap$" return &t.x[0] } @@ -1330,7 +1330,7 @@ func foo139() *byte { y byte } } - t := new(T) // ERROR "new\(T\) escapes to heap$" + t := new(T) // ERROR "new\(T\) escapes to heap$" return &t.x.y } @@ -1358,7 +1358,7 @@ func F2([]byte) //go:noescape -func F3(x []byte) // ERROR "F3 x does not escape$" +func F3(x []byte) // ERROR "x does not escape$" func F4(x []byte) // ERROR "leaking param: x$" @@ -1380,14 +1380,14 @@ type Tm struct { x int } -func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$" +func (t *Tm) M() { // ERROR "t does not escape$" } func foo141() { var f func() - t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" - f = t.M // ERROR "foo141 t.M does not escape$" + t := new(Tm) // ERROR "new\(Tm\) does not escape$" + f = t.M // ERROR "t.M does not escape$" _ = f } @@ -1401,7 +1401,7 @@ func foo142() { // issue 3888. func foo143() { for i := 0; i < 1000; i++ { - func() { // ERROR "foo143 func literal does not escape$" + func() { // ERROR "func literal does not escape$" for i := 0; i < 1; i++ { var t Tm t.M() @@ -1435,20 +1435,20 @@ type List struct { Next *List } -func foo145(l List) { // ERROR "foo145 l does not escape$" +func foo145(l List) { // ERROR "l does not escape$" var p *List for p = &l; p.Next != nil; p = p.Next { } } -func foo146(l List) { // ERROR "foo146 l does not escape$" +func foo146(l List) { // ERROR "l does not escape$" var p *List p = &l for ; p.Next != nil; p = p.Next { } } -func foo147(l List) { // ERROR "foo147 l does not escape$" +func foo147(l List) { // ERROR "l does not escape$" var p *List p = &l for p.Next != nil { @@ -1456,14 +1456,14 @@ func foo147(l List) { // ERROR "foo147 l does not escape$" } } -func foo148(l List) { // ERROR "foo148 l does not escape$" +func foo148(l List) { // ERROR "l does not escape$" for p := &l; p.Next != nil; p = p.Next { } } // related: address of variable should have depth of variable, not of loop -func foo149(l List) { // ERROR "foo149 l does not escape$" +func foo149(l List) { // ERROR "l does not escape$" var p *List for { for p = &l; p.Next != nil; p = p.Next { @@ -1498,7 +1498,7 @@ func bar151() { } func bar151b() { - var a [10]int // ERROR "moved to heap: a$" + var a [10]int // ERROR "moved to heap: a$" b := a[:] foo151(&b[4:8][0]) } @@ -1510,7 +1510,7 @@ func bar151c() { } func bar151d() { - var a [10]int // ERROR "moved to heap: a$" + var a [10]int // ERROR "moved to heap: a$" b := a[:] foo151(&b[4:8:8][0]) } @@ -1534,7 +1534,7 @@ func NewV(u U) *V { // ERROR "leaking param: u$" } func foo152() { - a := "a" // ERROR "moved to heap: a$" + a := "a" // ERROR "moved to heap: a$" u := U{&a} v := NewV(u) println(v) @@ -1542,7 +1542,7 @@ func foo152() { // issue 8176 - &x in type switch body not marked as escaping -func foo153(v interface{}) *int { // ERROR "foo153 v does not escape" +func foo153(v interface{}) *int { // ERROR "v does not escape" switch x := v.(type) { case int: // ERROR "moved to heap: x$" return &x @@ -1558,7 +1558,7 @@ func f() (x int, y *int) { // ERROR "moved to heap: x$" } func g() (x interface{}) { // ERROR "moved to heap: x$" - x = &x // ERROR "&x escapes to heap$" + x = &x return } @@ -1571,22 +1571,22 @@ type Lit struct { func ptrlitNoescape() { // Both literal and element do not escape. i := 0 - x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" + x := &Lit{&i} // ERROR "&Lit literal does not escape$" _ = x } func ptrlitNoEscape2() { // Literal does not escape, but element does. i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "ptrlitNoEscape2 &Lit literal does not escape$" - sink = *x // ERROR "\*x escapes to heap$" + x := &Lit{&i} // ERROR "&Lit literal 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$" - sink = x // ERROR "x escapes to heap$" + sink = x } // self-assignments @@ -1600,7 +1600,7 @@ type Buffer struct { str2 string } -func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$" +func (b *Buffer) foo() { // ERROR "b does not escape$" b.buf1 = b.buf1[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2\]$" b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2:3\]$" b.buf1 = b.buf2[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2\]$" @@ -1611,12 +1611,12 @@ func (b *Buffer) bar() { // ERROR "leaking param: b$" b.buf1 = b.arr[1:2] } -func (b *Buffer) arrayPtr() { // ERROR "\(\*Buffer\).arrayPtr b does not escape" +func (b *Buffer) arrayPtr() { // ERROR "b does not escape" b.buf1 = b.arrPtr[1:2] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2\]$" b.buf1 = b.arrPtr[1:2:3] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2:3\]$" } -func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$" +func (b *Buffer) baz() { // ERROR "b does not escape$" b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str1\[1:2\]$" b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str2\[1:2\]$" } @@ -1624,10 +1624,10 @@ func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$" func (b *Buffer) bat() { // ERROR "leaking param content: b$" o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$" o.buf1 = b.buf1[1:2] - sink = o // ERROR "o escapes to heap$" + sink = o } -func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$" +func quux(sp *string, bp *[]byte) { // ERROR "bp does not escape$" "sp does not escape$" *sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment in \*sp = \(\*sp\)\[1:2\]$" *bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment in \*bp = \(\*bp\)\[1:2\]$" } @@ -1642,7 +1642,7 @@ type StructWithString struct { // to just x, and thus &i looks escaping. func fieldFlowTracking() { var x StructWithString - i := 0 // ERROR "moved to heap: i$" + i := 0 // ERROR "moved to heap: i$" x.p = &i sink = x.s // ERROR "x.s escapes to heap$" } @@ -1650,27 +1650,27 @@ func fieldFlowTracking() { // String operations. func slicebytetostring0() { - b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "slicebytetostring0 string\(b\) does not escape$" + b := make([]byte, 20) // ERROR "make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) does not escape$" _ = s } func slicebytetostring1() { - b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "slicebytetostring1 string\(b\) does not escape$" + b := make([]byte, 20) // ERROR "make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) does not escape$" s1 := s[0:1] _ = s1 } func slicebytetostring2() { - b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$" + b := make([]byte, 20) // ERROR "make\(\[\]byte, 20\) does not escape$" s := string(b) // ERROR "string\(b\) escapes to heap$" s1 := s[0:1] // ERROR "moved to heap: s1$" - sink = &s1 // ERROR "&s1 escapes to heap$" + sink = &s1 } func slicebytetostring3() { - b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$" + b := make([]byte, 20) // ERROR "make\(\[\]byte, 20\) does not escape$" s := string(b) // ERROR "string\(b\) escapes to heap$" s1 := s[0:1] sink = s1 // ERROR "s1 escapes to heap$" @@ -1679,7 +1679,7 @@ func slicebytetostring3() { func addstr0() { s0 := "a" s1 := "b" - s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$" + s := s0 + s1 // ERROR "s0 \+ s1 does not escape$" _ = s } @@ -1687,14 +1687,14 @@ func addstr1() { s0 := "a" s1 := "b" s := "c" - s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$" + s += s0 + s1 // ERROR "s0 \+ s1 does not escape$" _ = s } func addstr2() { - b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$" + b := make([]byte, 20) // ERROR "make\(\[\]byte, 20\) does not escape$" s0 := "a" - s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$" + s := string(b) + s0 // ERROR "string\(b\) \+ s0 does not escape$" "string\(b\) does not escape$" _ = s } @@ -1709,7 +1709,7 @@ func addstr3() { func intstring0() bool { // string does not escape x := '0' - s := string(x) // ERROR "intstring0 string\(x\) does not escape$" + s := string(x) // ERROR "string\(x\) does not escape$" return s == "0" } @@ -1724,12 +1724,12 @@ func intstring2() { // string escapes to heap x := '0' s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$" - sink = &s // ERROR "&s escapes to heap$" + sink = &s } func stringtoslicebyte0() { s := "foo" - x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$" + x := []byte(s) // ERROR "\(\[\]byte\)\(s\) does not escape$" _ = x } @@ -1745,7 +1745,7 @@ func stringtoslicebyte2() { func stringtoslicerune0() { s := "foo" - x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$" + x := []rune(s) // ERROR "\(\[\]rune\)\(s\) does not escape$" _ = x } @@ -1760,23 +1760,23 @@ func stringtoslicerune2() { } func slicerunetostring0() { - r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$" - s := string(r) // ERROR "slicerunetostring0 string\(r\) does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" + s := string(r) // ERROR "string\(r\) does not escape$" _ = s } func slicerunetostring1() string { - r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" return string(r) // ERROR "string\(r\) escapes to heap$" } func slicerunetostring2() { - r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" sink = string(r) // ERROR "string\(r\) escapes to heap$" } func makemap0() { - m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$" + m := make(map[int]int) // ERROR "make\(map\[int\]int\) does not escape$" m[0] = 0 m[1]++ delete(m, 1) @@ -1789,15 +1789,15 @@ func makemap1() map[int]int { func makemap2() { m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" - sink = m // ERROR "m escapes to heap$" + sink = m } -func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$" - return m["foo"] // ERROR "nonescapingEface .foo. does not escape$" +func nonescapingEface(m map[interface{}]bool) bool { // ERROR "m does not escape$" + return m["foo"] // ERROR ".foo. does not escape$" } -func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$" - return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$" +func nonescapingIface(m map[M]bool) bool { // ERROR "m does not escape$" + return m[MV(0)] // ERROR "MV\(0\) does not escape$" } func issue10353() { diff --git a/test/escape2n.go b/test/escape2n.go index 2fd26f7c..f771e0ae 100644 --- a/test/escape2n.go +++ b/test/escape2n.go @@ -1,4 +1,4 @@ -// errorcheck -0 -N -m -l -newescape=true +// errorcheck -0 -N -m -l // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -37,24 +37,24 @@ func foo3b(t T) { // ERROR "leaking param: t$" } // xx isn't going anywhere, so use of yy is ok -func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$" +func foo4(xx, yy *int) { // ERROR "xx does not escape$" "yy does not escape$" xx = yy } // xx isn't going anywhere, so taking address of yy is ok -func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$" +func foo5(xx **int, yy *int) { // ERROR "xx does not escape$" "yy does not escape$" xx = &yy } -func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$" +func foo6(xx **int, yy *int) { // ERROR "xx does not escape$" "leaking param: yy$" *xx = yy } -func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$" +func foo7(xx **int, yy *int) { // ERROR "xx does not escape$" "yy does not escape$" **xx = *yy } -func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$" +func foo8(xx, yy *int) int { // ERROR "xx does not escape$" "yy does not escape$" xx = yy return *xx } @@ -64,7 +64,7 @@ func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$ return xx } -func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$" +func foo10(xx, yy *int) { // ERROR "xx does not escape$" "yy does not escape$" *xx = *yy } @@ -88,7 +88,7 @@ func foo13(yyy **int) { // ERROR "leaking param content: yyy$" *xxx = *yyy } -func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$" +func foo14(yyy **int) { // ERROR "yyy does not escape$" **xxx = **yyy } @@ -100,7 +100,7 @@ func foo16(yy *int) { // ERROR "leaking param: yy$" *xxx = yy } -func foo17(yy *int) { // ERROR "foo17 yy does not escape$" +func foo17(yy *int) { // ERROR "yy does not escape$" **xxx = *yy } @@ -125,11 +125,11 @@ func NewBarp(x *int) *Bar { // ERROR "leaking param: x$" return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" } -func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$" +func NewBarp2(x *int) *Bar { // ERROR "x does not escape$" return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$" } -func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$" +func (b *Bar) NoLeak() int { // ERROR "b does not escape$" return *(b.ii) } @@ -146,18 +146,18 @@ func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$ } func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$" - v := 0 // ERROR "moved to heap: v$" + v := 0 // ERROR "moved to heap: v$" b.ii = &v return b.ii } func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$" - v := 0 // ERROR "moved to heap: v$" + v := 0 // ERROR "moved to heap: v$" b.ii = &v return b.ii } -func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$" +func (b Bar) StillNoLeak() int { // ERROR "b does not escape$" v := 0 b.ii = &v return b.i @@ -176,7 +176,7 @@ func NewBar2() *Bar2 { return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$" } -func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$" +func (b *Bar2) NoLeak() int { // ERROR "b does not escape$" return b.i[0] } @@ -188,7 +188,7 @@ func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 lev return b.ii[0:1] } -func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$" +func (b Bar2) AgainNoLeak() [12]int { // ERROR "b does not escape$" return b.i } @@ -219,7 +219,7 @@ func foo21a() func() int { func foo22() int { x := 42 - return func() int { // ERROR "foo22 func literal does not escape$" + return func() int { // ERROR "func literal does not escape$" return x }() } @@ -250,7 +250,7 @@ func foo23c(x int) func() int { // ERROR "moved to heap: x$" } func foo24(x int) int { - return func() int { // ERROR "foo24 func literal does not escape$" + return func() int { // ERROR "func literal does not escape$" return x }() } @@ -262,7 +262,7 @@ func fooleak(xx *int) int { // ERROR "leaking param: xx$" return *x } -func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$" +func foonoleak(xx *int) int { // ERROR "xx does not escape$" return *x + *xx } @@ -286,7 +286,7 @@ func (f *Foo) fooleak() { // ERROR "leaking param: f$" pf = f } -func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$" +func (f *Foo) foonoleak() { // ERROR "f does not escape$" F.x = f.x } @@ -294,7 +294,7 @@ func (f *Foo) Leak() { // ERROR "leaking param: f$" f.fooleak() } -func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$" +func (f *Foo) NoLeak() { // ERROR "f does not escape$" f.foonoleak() } @@ -302,11 +302,11 @@ func foo41(x int) { // ERROR "moved to heap: x$" F.xx = &x } -func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$" +func (f *Foo) foo42(x int) { // ERROR "f does not escape$" "moved to heap: x$" f.xx = &x } -func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$" +func foo43(f *Foo, x int) { // ERROR "f does not escape$" "moved to heap: x$" f.xx = &x } @@ -314,7 +314,7 @@ func foo44(yy *int) { // ERROR "leaking param: yy$" F.xx = yy } -func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$" +func (f *Foo) foo45() { // ERROR "f does not escape$" F.x = f.x } @@ -407,7 +407,7 @@ func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" return a[1] } -func foo60a(i *int) *int { // ERROR "foo60a i does not escape$" +func foo60a(i *int) *int { // ERROR "i does not escape$" var a [12]*int a[0] = i return nil @@ -423,7 +423,7 @@ func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" return s.b } -func foo61a(i *int) *int { // ERROR "foo61a i does not escape$" +func foo61a(i *int) *int { // ERROR "i does not escape$" type S struct { a, b *int } @@ -439,7 +439,7 @@ func foo62(i *int) *int { // ERROR "leaking param: i$" type S struct { a, b *int } - s := new(S) // ERROR "foo62 new\(S\) does not escape$" + s := new(S) // ERROR "new\(S\) does not escape$" s.a = i return nil // s.b } @@ -448,7 +448,7 @@ type M interface { M() } -func foo63(m M) { // ERROR "foo63 m does not escape$" +func foo63(m M) { // ERROR "m does not escape$" } func foo64(m M) { // ERROR "leaking param: m$" @@ -465,17 +465,17 @@ func (MV) M() {} func foo65() { var mv MV - foo63(&mv) // ERROR "foo65 &mv does not escape$" + foo63(&mv) } func foo66() { - var mv MV // ERROR "moved to heap: mv$" - foo64(&mv) // ERROR "&mv escapes to heap$" + var mv MV // ERROR "moved to heap: mv$" + foo64(&mv) } func foo67() { var mv MV - foo63(mv) // ERROR "foo67 mv does not escape$" + foo63(mv) // ERROR "mv does not escape$" } func foo68() { @@ -489,7 +489,7 @@ func foo69(m M) { // ERROR "leaking param: m$" } func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$" - m = mv1 // ERROR "mv1 escapes to heap$" + m = mv1 foo64(m) } @@ -522,7 +522,7 @@ func foo72a() { var y [10]*int for i := 0; i < 10; i++ { // escapes its scope - x := i // ERROR "moved to heap: x$" + x := i // ERROR "moved to heap: x$" y[i] = &x } return @@ -531,7 +531,7 @@ func foo72a() { func foo72b() [10]*int { var y [10]*int for i := 0; i < 10; i++ { - x := i // ERROR "moved to heap: x$" + x := i // ERROR "moved to heap: x$" y[i] = &x } return y @@ -539,7 +539,7 @@ func foo72b() [10]*int { // issue 2145 func foo73() { - s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal 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 "foo731 \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal 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 "foo74 \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal 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 "foo74a \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal 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 "foo74b \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal 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 "foo74c \[\]int literal does not escape$" + s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape$" for i, v := range s { vv := v // ERROR "moved to heap: vv$" // actually just escapes its scope @@ -611,57 +611,57 @@ func foo74c() { } } -func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$" +func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "x does not escape$" return y } -func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$" +func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "y does not escape$" return &x[0] } -func foo75(z *int) { // ERROR "foo75 z does not escape$" - myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75 ... argument does not escape$" +func foo75(z *int) { // ERROR "z does not escape$" + myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } -func foo75a(z *int) { // ERROR "foo75a z does not escape$" - myprint1(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75a ... argument does not escape$" +func foo75a(z *int) { // ERROR "z does not escape$" + myprint1(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } func foo75esc(z *int) { // ERROR "leaking param: z$" - gxx = myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75esc ... argument does not escape$" + gxx = myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } -func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$" +func foo75aesc(z *int) { // ERROR "z does not escape$" var ppi **interface{} // assignments to pointer dereferences lose track *ppi = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" } -func foo75aesc1(z *int) { // ERROR "foo75aesc1 z does not escape$" - sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$" +func foo75aesc1(z *int) { // ERROR "z does not escape$" + sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" } func foo76(z *int) { // ERROR "z does not escape" - myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z does not escape" + myprint(nil, z) // ERROR "... argument does not escape$" } func foo76a(z *int) { // ERROR "z does not escape" - myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z does not escape" + myprint1(nil, z) // ERROR "... argument does not escape$" } func foo76b() { - myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76b ... argument does not escape$" + myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } func foo76c() { - myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76c ... argument does not escape$" + myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } func foo76d() { - defer myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76d ... argument does not escape$" + defer myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } func foo76e() { - defer myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76e ... argument does not escape$" + defer myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "... argument does not escape$" } func foo76f() { @@ -677,11 +677,11 @@ func foo76g() { } } -func foo77(z []interface{}) { // ERROR "foo77 z does not escape$" +func foo77(z []interface{}) { // ERROR "z does not escape$" myprint(nil, z...) // z does not escape } -func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$" +func foo77a(z []interface{}) { // ERROR "z does not escape$" myprint1(nil, z...) } @@ -691,15 +691,15 @@ func foo77b(z []interface{}) { // ERROR "leaking param: z$" } func foo77c(z []interface{}) { // ERROR "leaking param: z$" - sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$" + sink = myprint1(nil, z...) } func dotdotdot() { i := 0 - myprint(nil, &i) // ERROR "&i does not escape" "dotdotdot ... argument does not escape$" + myprint(nil, &i) // ERROR "... argument does not escape$" j := 0 - myprint1(nil, &j) // ERROR "&j does not escape" "dotdotdot ... argument does not escape$" + myprint1(nil, &j) // ERROR "... argument does not escape$" } func foo78(z int) *int { // ERROR "moved to heap: z$" @@ -728,7 +728,7 @@ func foo80() *int { func foo81() *int { for { - z := new(int) // ERROR "foo81 new\(int\) does not escape$" + z := new(int) // ERROR "new\(int\) does not escape$" _ = z } return nil @@ -736,14 +736,14 @@ func foo81() *int { func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$" -func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$" +func noop(x, y *int) {} // ERROR "x does not escape$" "y does not escape$" func foo82() { - var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" + var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" go noop(tee(&z)) go noop(&x, &y) for { - var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" + var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" defer noop(tee(&u)) defer noop(&v, &w) } @@ -775,7 +775,7 @@ func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" } // does not leak c -func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$" +func foo93(c chan *int) *int { // ERROR "c does not escape$" for v := range c { return v } @@ -794,7 +794,7 @@ func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result } // does leak x -func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$" +func foo95(m map[*int]*int, x *int) { // ERROR "m does not escape$" "leaking param: x$" m[x] = x } @@ -809,7 +809,7 @@ func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" } // does not leak m -func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$" +func foo98(m map[int]*int) *int { // ERROR "m does not escape$" return m[0] } @@ -835,7 +835,7 @@ func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" } // does not leak m -func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" +func foo101a(m [1]*int) *int { // ERROR "m does not escape$" for i := range m { // ERROR "moved to heap: i$" return &i } @@ -843,12 +843,12 @@ func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" } // does leak x -func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$" +func foo102(m []*int, x *int) { // ERROR "m does not escape$" "leaking param: x$" m[0] = x } // does not leak x -func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$" +func foo103(m [1]*int, x *int) { // ERROR "m does not escape$" "x does not escape$" m[0] = x } @@ -878,7 +878,7 @@ func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$" } func foo109(x *int) *int { // ERROR "leaking param: x$" - m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$" + m := map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal 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 "foo110 map\[\*int\]\*int literal does not escape$" + m := map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal does not escape$" return m[nil] } func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" - m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$" + m := []*int{x} // ERROR "\[\]\*int literal 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 "foo114 &Bar literal does not escape$" + m := &Bar{ii: x} // ERROR "&Bar literal does not escape$" return m.ii } @@ -916,22 +916,22 @@ func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" func foo116(b bool) *int { if b { - x := 1 // ERROR "moved to heap: x$" + x := 1 // ERROR "moved to heap: x$" return &x } else { - y := 1 // ERROR "moved to heap: y$" + y := 1 // ERROR "moved to heap: y$" return &y } return nil } -func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$" - x := 1 // ERROR "moved to heap: x$" - unknown(&x) // ERROR "&x escapes to heap$" +func foo117(unknown func(interface{})) { // ERROR "unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" + unknown(&x) } -func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$" - x := 1 // ERROR "moved to heap: x$" +func foo118(unknown func(*int)) { // ERROR "unknown does not escape$" + x := 1 // ERROR "moved to heap: x$" unknown(&x) } @@ -1167,7 +1167,7 @@ func foo122() { goto L1 L1: - i = new(int) // ERROR "foo122 new\(int\) does not escape$" + i = new(int) // ERROR "new\(int\) does not escape$" _ = i } @@ -1182,18 +1182,18 @@ L1: _ = i } -func foo124(x **int) { // ERROR "foo124 x does not escape$" +func foo124(x **int) { // ERROR "x does not escape$" var i int // ERROR "moved to heap: i$" p := &i - func() { // ERROR "foo124 func literal does not escape$" + func() { // ERROR "func literal does not escape$" *x = p }() } -func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$" +func foo125(ch chan *int) { // ERROR "ch does not escape$" var i int // ERROR "moved to heap: i$" p := &i - func() { // ERROR "foo125 func literal does not escape$" + func() { // ERROR "func literal does not escape$" ch <- p }() } @@ -1203,7 +1203,7 @@ func foo126() { for { // loopdepth 1 var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo126 func literal does not escape$" + func() { // ERROR "func literal does not escape$" px = &i }() } @@ -1229,9 +1229,9 @@ func foo128() { func foo129() { var i int // ERROR "moved to heap: i$" p := &i - func() { // ERROR "foo129 func literal does not escape$" + func() { // ERROR "func literal does not escape$" q := p - func() { // ERROR "foo129.func1 func literal does not escape$" + func() { // ERROR "func literal does not escape$" r := q px = r }() @@ -1241,7 +1241,7 @@ func foo129() { func foo130() { for { var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo130 func literal does not escape$" + func() { // ERROR "func literal does not escape$" px = &i }() } @@ -1249,7 +1249,7 @@ func foo130() { func foo131() { var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo131 func literal does not escape$" + func() { // ERROR "func literal does not escape$" px = &i }() } @@ -1263,7 +1263,7 @@ func foo132() { func foo133() { var i int // ERROR "moved to heap: i$" - defer func() { // ERROR "foo133 func literal does not escape$" + defer func() { // ERROR "func literal does not escape$" px = &i }() } @@ -1271,9 +1271,9 @@ func foo133() { func foo134() { var i int p := &i - func() { // ERROR "foo134 func literal does not escape$" + func() { // ERROR "func literal does not escape$" q := p - func() { // ERROR "foo134.func1 func literal does not escape$" + func() { // ERROR "func literal does not escape$" r := q _ = r }() @@ -1281,11 +1281,11 @@ func foo134() { } func foo135() { - var i int // ERROR "moved to heap: i$" + var i int // ERROR "moved to heap: i$" p := &i go func() { // ERROR "func literal escapes to heap$" q := p - func() { // ERROR "foo135.func1 func literal does not escape$" + func() { // ERROR "func literal does not escape$" r := q _ = r }() @@ -1293,11 +1293,11 @@ func foo135() { } func foo136() { - var i int // ERROR "moved to heap: i$" + var i int // ERROR "moved to heap: i$" p := &i go func() { // ERROR "func literal escapes to heap$" q := p - func() { // ERROR "foo136.func1 func literal does not escape$" + func() { // ERROR "func literal does not escape$" r := q px = r }() @@ -1307,7 +1307,7 @@ func foo136() { func foo137() { var i int // ERROR "moved to heap: i$" p := &i - func() { // ERROR "foo137 func literal does not escape$" + func() { // ERROR "func literal does not escape$" q := p go func() { // ERROR "func literal escapes to heap$" r := q @@ -1320,7 +1320,7 @@ func foo138() *byte { type T struct { x [1]byte } - t := new(T) // ERROR "new\(T\) escapes to heap$" + t := new(T) // ERROR "new\(T\) escapes to heap$" return &t.x[0] } @@ -1330,7 +1330,7 @@ func foo139() *byte { y byte } } - t := new(T) // ERROR "new\(T\) escapes to heap$" + t := new(T) // ERROR "new\(T\) escapes to heap$" return &t.x.y } @@ -1358,7 +1358,7 @@ func F2([]byte) //go:noescape -func F3(x []byte) // ERROR "F3 x does not escape$" +func F3(x []byte) // ERROR "x does not escape$" func F4(x []byte) // ERROR "leaking param: x$" @@ -1380,14 +1380,14 @@ type Tm struct { x int } -func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$" +func (t *Tm) M() { // ERROR "t does not escape$" } func foo141() { var f func() - t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" - f = t.M // ERROR "foo141 t.M does not escape$" + t := new(Tm) // ERROR "new\(Tm\) does not escape$" + f = t.M // ERROR "t.M does not escape$" _ = f } @@ -1401,7 +1401,7 @@ func foo142() { // issue 3888. func foo143() { for i := 0; i < 1000; i++ { - func() { // ERROR "foo143 func literal does not escape$" + func() { // ERROR "func literal does not escape$" for i := 0; i < 1; i++ { var t Tm t.M() @@ -1435,20 +1435,20 @@ type List struct { Next *List } -func foo145(l List) { // ERROR "foo145 l does not escape$" +func foo145(l List) { // ERROR "l does not escape$" var p *List for p = &l; p.Next != nil; p = p.Next { } } -func foo146(l List) { // ERROR "foo146 l does not escape$" +func foo146(l List) { // ERROR "l does not escape$" var p *List p = &l for ; p.Next != nil; p = p.Next { } } -func foo147(l List) { // ERROR "foo147 l does not escape$" +func foo147(l List) { // ERROR "l does not escape$" var p *List p = &l for p.Next != nil { @@ -1456,14 +1456,14 @@ func foo147(l List) { // ERROR "foo147 l does not escape$" } } -func foo148(l List) { // ERROR "foo148 l does not escape$" +func foo148(l List) { // ERROR "l does not escape$" for p := &l; p.Next != nil; p = p.Next { } } // related: address of variable should have depth of variable, not of loop -func foo149(l List) { // ERROR "foo149 l does not escape$" +func foo149(l List) { // ERROR "l does not escape$" var p *List for { for p = &l; p.Next != nil; p = p.Next { @@ -1498,7 +1498,7 @@ func bar151() { } func bar151b() { - var a [10]int // ERROR "moved to heap: a$" + var a [10]int // ERROR "moved to heap: a$" b := a[:] foo151(&b[4:8][0]) } @@ -1510,7 +1510,7 @@ func bar151c() { } func bar151d() { - var a [10]int // ERROR "moved to heap: a$" + var a [10]int // ERROR "moved to heap: a$" b := a[:] foo151(&b[4:8:8][0]) } @@ -1534,7 +1534,7 @@ func NewV(u U) *V { // ERROR "leaking param: u$" } func foo152() { - a := "a" // ERROR "moved to heap: a$" + a := "a" // ERROR "moved to heap: a$" u := U{&a} v := NewV(u) println(v) @@ -1542,7 +1542,7 @@ func foo152() { // issue 8176 - &x in type switch body not marked as escaping -func foo153(v interface{}) *int { // ERROR "foo153 v does not escape" +func foo153(v interface{}) *int { // ERROR "v does not escape" switch x := v.(type) { case int: // ERROR "moved to heap: x$" return &x @@ -1558,7 +1558,7 @@ func f() (x int, y *int) { // ERROR "moved to heap: x$" } func g() (x interface{}) { // ERROR "moved to heap: x$" - x = &x // ERROR "&x escapes to heap$" + x = &x return } @@ -1571,22 +1571,22 @@ type Lit struct { func ptrlitNoescape() { // Both literal and element do not escape. i := 0 - x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" + x := &Lit{&i} // ERROR "&Lit literal does not escape$" _ = x } func ptrlitNoEscape2() { // Literal does not escape, but element does. i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "ptrlitNoEscape2 &Lit literal does not escape$" - sink = *x // ERROR "\*x escapes to heap$" + x := &Lit{&i} // ERROR "&Lit literal 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$" - sink = x // ERROR "x escapes to heap$" + sink = x } // self-assignments @@ -1600,7 +1600,7 @@ type Buffer struct { str2 string } -func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$" +func (b *Buffer) foo() { // ERROR "b does not escape$" b.buf1 = b.buf1[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2\]$" b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2:3\]$" b.buf1 = b.buf2[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2\]$" @@ -1611,12 +1611,12 @@ func (b *Buffer) bar() { // ERROR "leaking param: b$" b.buf1 = b.arr[1:2] } -func (b *Buffer) arrayPtr() { // ERROR "\(\*Buffer\).arrayPtr b does not escape" +func (b *Buffer) arrayPtr() { // ERROR "b does not escape" b.buf1 = b.arrPtr[1:2] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2\]$" b.buf1 = b.arrPtr[1:2:3] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2:3\]$" } -func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$" +func (b *Buffer) baz() { // ERROR "b does not escape$" b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str1\[1:2\]$" b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str2\[1:2\]$" } @@ -1624,10 +1624,10 @@ func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$" func (b *Buffer) bat() { // ERROR "leaking param content: b$" o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$" o.buf1 = b.buf1[1:2] - sink = o // ERROR "o escapes to heap$" + sink = o } -func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$" +func quux(sp *string, bp *[]byte) { // ERROR "bp does not escape$" "sp does not escape$" *sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment in \*sp = \(\*sp\)\[1:2\]$" *bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment in \*bp = \(\*bp\)\[1:2\]$" } @@ -1642,7 +1642,7 @@ type StructWithString struct { // to just x, and thus &i looks escaping. func fieldFlowTracking() { var x StructWithString - i := 0 // ERROR "moved to heap: i$" + i := 0 // ERROR "moved to heap: i$" x.p = &i sink = x.s // ERROR "x.s escapes to heap$" } @@ -1650,27 +1650,27 @@ func fieldFlowTracking() { // String operations. func slicebytetostring0() { - b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "slicebytetostring0 string\(b\) does not escape$" + b := make([]byte, 20) // ERROR "make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) does not escape$" _ = s } func slicebytetostring1() { - b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "slicebytetostring1 string\(b\) does not escape$" + b := make([]byte, 20) // ERROR "make\(\[\]byte, 20\) does not escape$" + s := string(b) // ERROR "string\(b\) does not escape$" s1 := s[0:1] _ = s1 } func slicebytetostring2() { - b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$" + b := make([]byte, 20) // ERROR "make\(\[\]byte, 20\) does not escape$" s := string(b) // ERROR "string\(b\) escapes to heap$" s1 := s[0:1] // ERROR "moved to heap: s1$" - sink = &s1 // ERROR "&s1 escapes to heap$" + sink = &s1 } func slicebytetostring3() { - b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$" + b := make([]byte, 20) // ERROR "make\(\[\]byte, 20\) does not escape$" s := string(b) // ERROR "string\(b\) escapes to heap$" s1 := s[0:1] sink = s1 // ERROR "s1 escapes to heap$" @@ -1679,7 +1679,7 @@ func slicebytetostring3() { func addstr0() { s0 := "a" s1 := "b" - s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$" + s := s0 + s1 // ERROR "s0 \+ s1 does not escape$" _ = s } @@ -1687,14 +1687,14 @@ func addstr1() { s0 := "a" s1 := "b" s := "c" - s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$" + s += s0 + s1 // ERROR "s0 \+ s1 does not escape$" _ = s } func addstr2() { - b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$" + b := make([]byte, 20) // ERROR "make\(\[\]byte, 20\) does not escape$" s0 := "a" - s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$" + s := string(b) + s0 // ERROR "string\(b\) \+ s0 does not escape$" "string\(b\) does not escape$" _ = s } @@ -1709,7 +1709,7 @@ func addstr3() { func intstring0() bool { // string does not escape x := '0' - s := string(x) // ERROR "intstring0 string\(x\) does not escape$" + s := string(x) // ERROR "string\(x\) does not escape$" return s == "0" } @@ -1724,12 +1724,12 @@ func intstring2() { // string escapes to heap x := '0' s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$" - sink = &s // ERROR "&s escapes to heap$" + sink = &s } func stringtoslicebyte0() { s := "foo" - x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$" + x := []byte(s) // ERROR "\(\[\]byte\)\(s\) does not escape$" _ = x } @@ -1745,7 +1745,7 @@ func stringtoslicebyte2() { func stringtoslicerune0() { s := "foo" - x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$" + x := []rune(s) // ERROR "\(\[\]rune\)\(s\) does not escape$" _ = x } @@ -1760,23 +1760,23 @@ func stringtoslicerune2() { } func slicerunetostring0() { - r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$" - s := string(r) // ERROR "slicerunetostring0 string\(r\) does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" + s := string(r) // ERROR "string\(r\) does not escape$" _ = s } func slicerunetostring1() string { - r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" return string(r) // ERROR "string\(r\) escapes to heap$" } func slicerunetostring2() { - r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$" + r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape$" sink = string(r) // ERROR "string\(r\) escapes to heap$" } func makemap0() { - m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$" + m := make(map[int]int) // ERROR "make\(map\[int\]int\) does not escape$" m[0] = 0 m[1]++ delete(m, 1) @@ -1789,15 +1789,15 @@ func makemap1() map[int]int { func makemap2() { m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" - sink = m // ERROR "m escapes to heap$" + sink = m } -func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$" - return m["foo"] // ERROR "nonescapingEface .foo. does not escape$" +func nonescapingEface(m map[interface{}]bool) bool { // ERROR "m does not escape$" + return m["foo"] // ERROR ".foo. does not escape$" } -func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$" - return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$" +func nonescapingIface(m map[M]bool) bool { // ERROR "m does not escape$" + return m[MV(0)] // ERROR "MV\(0\) does not escape$" } func issue10353() { diff --git a/test/escape5.go b/test/escape5.go index 11cab629..061e57a0 100644 --- a/test/escape5.go +++ b/test/escape5.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l -newescape=true +// errorcheck -0 -m -l // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -139,7 +139,7 @@ func f8(p *T1) (k T2) { // ERROR "leaking param: p$" } // should make p leak always - global = p // ERROR "p escapes to heap" + global = p return T2{p} } @@ -164,7 +164,7 @@ func f13() { var x *int f11(&x) f12(&x) - runtime.KeepAlive(&x) // ERROR "&x does not escape" + runtime.KeepAlive(&x) } // Test for issue 24305 (passing to unnamed receivers does not escape). diff --git a/test/escape_array.go b/test/escape_array.go index d363b98e..0d07fd86 100644 --- a/test/escape_array.go +++ b/test/escape_array.go @@ -71,7 +71,7 @@ func fuo(x *U, y *U) *string { // ERROR "leaking param: x to result ~r2 level=1$ // pointers stored in small array literals do not escape; // large array literals are heap allocated; // pointers stored in large array literals escape. -func hugeLeaks1(x **string, y **string) { // ERROR "leaking param content: x" "hugeLeaks1 y does not escape" +func hugeLeaks1(x **string, y **string) { // ERROR "leaking param content: x" "y does not escape" a := [10]*string{*y} _ = a // 4 x 4,000,000 exceeds MaxStackVarSize, therefore it must be heap allocated if pointers are 4 bytes or larger. @@ -79,7 +79,7 @@ func hugeLeaks1(x **string, y **string) { // ERROR "leaking param content: x" "h _ = b } -func hugeLeaks2(x *string, y *string) { // ERROR "leaking param: x" "hugeLeaks2 y does not escape" +func hugeLeaks2(x *string, y *string) { // ERROR "leaking param: x" "y does not escape" a := [10]*string{y} _ = a // 4 x 4,000,000 exceeds MaxStackVarSize, therefore it must be heap allocated if pointers are 4 bytes or larger. diff --git a/test/escape_because.go b/test/escape_because.go deleted file mode 100644 index e0a4214e..00000000 --- a/test/escape_because.go +++ /dev/null @@ -1,209 +0,0 @@ -// errorcheck -0 -m -m -l -newescape=false - -// Copyright 2015 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. - -// Note the doubled -m; this tests the "because" explanations for escapes, -// and is likely to be annoyingly fragile under compiler change. -// As long as the explanations look reasonably sane, meaning eyeball verify output of -// go build -gcflags '-l -m -m' escape_because.go -// and investigate changes, feel free to update with -// go run run.go -update_errors -- escape_because.go - -package main - -func main() { -} - -var sink interface{} - -type pair struct { - x, y *int -} - -type Pairy interface { - EqualParts() bool -} - -func (p *pair) EqualParts() bool { // ERROR "\(\*pair\).EqualParts p does not escape$" - return p != nil && (p.x == p.y || *p.x == *p.y) -} - -func f1(p *int) { // ERROR "from \[3\]\*int literal \(array literal element\) at escape_because.go:34$" "from a \(assigned\) at escape_because.go:34$" "from a \(interface-converted\) at escape_because.go:35$" "from sink \(assigned to top level variable\) at escape_because.go:35$" "leaking param: p$" - a := [3]*int{p, nil, nil} - sink = a // ERROR "a escapes to heap$" "from sink \(assigned to top level variable\) at escape_because.go:35$" - -} - -func f2(q *int) { // ERROR "from &u \(address-of\) at escape_because.go:43$" "from &u \(interface-converted\) at escape_because.go:43$" "from pair literal \(struct literal element\) at escape_because.go:41$" "from s \(assigned\) at escape_because.go:40$" "from sink \(assigned to top level variable\) at escape_because.go:43$" "from t \(assigned\) at escape_because.go:41$" "from u \(assigned\) at escape_because.go:42$" "leaking param: q$" - s := q - t := pair{s, nil} - u := t // ERROR "moved to heap: u$" - sink = &u // ERROR "&u escapes to heap$" "from sink \(assigned to top level variable\) at escape_because.go:43$" -} - -func f3(r *int) interface{} { // ERROR "from \[\]\*int literal \(slice-literal-element\) at escape_because.go:47$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$" "leaking param: r" - c := []*int{r} // ERROR "\[\]\*int literal escapes to heap$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$" - return c // "return" // ERROR "c escapes to heap$" "from ~r1 \(return\) at escape_because.go:48$" -} - -func f4(a *int, s []*int) int { // ERROR "from \*s \(indirection\) at escape_because.go:51$" "from append\(s, a\) \(appended to slice\) at escape_because.go:52$" "from append\(s, a\) \(appendee slice\) at escape_because.go:52$" "leaking param content: s$" "leaking param: a$" - s = append(s, a) - return *(s[0]) -} - -func f5(s1, s2 []*int) int { // ERROR "from \*s1 \(indirection\) at escape_because.go:56$" "from \*s2 \(indirection\) at escape_because.go:56$" "from append\(s1, s2...\) \(appended slice...\) at escape_because.go:57$" "from append\(s1, s2...\) \(appendee slice\) at escape_because.go:57$" "leaking param content: s1$" "leaking param content: s2$" - s1 = append(s1, s2...) - return *(s1[0]) -} - -func f6(x, y *int) bool { // ERROR "f6 x does not escape$" "f6 y does not escape$" - p := pair{x, y} - var P Pairy = &p // ERROR "f6 &p does not escape$" - pp := P.(*pair) - return pp.EqualParts() -} - -func f7(x map[int]*int, y int) *int { // ERROR "f7 x does not escape$" - z, ok := x[y] - if !ok { - return nil - } - return z -} - -func f8(x int, y *int) *int { // ERROR "from ~r2 \(return\) at escape_because.go:78$" "from ~r2 \(returned from recursive function\) at escape_because.go:76$" "leaking param: y$" "moved to heap: x$" - if x <= 0 { - return y - } - x-- - return f8(*y, &x) -} - -func f9(x int, y ...*int) *int { // ERROR "from y\[0\] \(dot of pointer\) at escape_because.go:86$" "from ~r2 \(return\) at escape_because.go:86$" "from ~r2 \(returned from recursive function\) at escape_because.go:84$" "leaking param content: y$" "leaking param: y to result ~r2 level=1$" "moved to heap: x$" - if x <= 0 { - return y[0] - } - x-- - return f9(*y[0], &x) // ERROR "f9 ... argument does not escape$" -} - -func f10(x map[*int]*int, y, z *int) *int { // ERROR "f10 x does not escape$" "from x\[y\] \(key of map put\) at escape_because.go:93$" "from x\[y\] \(value of map put\) at escape_because.go:93$" "leaking param: y$" "leaking param: z$" - x[y] = z - return z -} - -func f11(x map[*int]*int, y, z *int) map[*int]*int { // ERROR "f11 x does not escape$" "from map\[\*int\]\*int literal \(map literal key\) at escape_because.go:98$" "from map\[\*int\]\*int literal \(map literal value\) at escape_because.go:98$" "leaking param: y$" "leaking param: z$" - return map[*int]*int{y: z} // ERROR "from ~r3 \(return\) at escape_because.go:98$" "map\[\*int\]\*int literal escapes to heap$" -} - -func f12() { - b := []byte("test") // ERROR "\(\[\]byte\)\(.test.\) escapes to heap$" "from b \(assigned\) at escape_because.go:102$" "from b \(passed to call\[argument escapes\]\) at escape_because.go:103$" - escape(b) -} - -func escape(b []byte) { // ERROR "from panic\(b\) \(panic\) at escape_because.go:107$" "leaking param: b$" - panic(b) -} - -func f13() { - b := []byte("test") // ERROR "\(\[\]byte\)\(.test.\) escapes to heap$" "from .out0 \(passed-to-and-returned-from-call\) at escape_because.go:112$" "from b \(assigned\) at escape_because.go:111$" "from c \(assigned\) at escape_because.go:112$" "from c \(passed to call\[argument escapes\]\) at escape_because.go:113$" - c := transmit(b) - escape(c) -} - -func transmit(b []byte) []byte { // ERROR "from ~r1 \(return\) at escape_because.go:117$" "leaking param: b to result ~r1 level=0$" - return b -} - -func f14() { - n := 32 - s1 := make([]int, n) // ERROR "make\(\[\]int, n\) escapes to heap" "from make\(\[\]int, n\) \(non-constant size\)" - s2 := make([]int, 0, n) // ERROR "make\(\[\]int, 0, n\) escapes to heap" "from make\(\[\]int, 0, n\) \(non-constant size\)" - _, _ = s1, s2 -} - -func leakParams(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r2 level=0$" "from ~r2 \(return\) at escape_because.go:128$" "leaking param: p2 to result ~r3 level=0$" "from ~r3 \(return\) at escape_because.go:128$" - return p1, p2 -} - -func leakThroughOAS2() { - // See #26987. - i := 0 // ERROR "moved to heap: i$" - j := 0 // ERROR "moved to heap: j$" - sink, sink = &i, &j // ERROR "&i escapes to heap$" "from sink \(assign-pair\) at escape_because.go:135$" "&j escapes to heap$" -} - -func leakThroughOAS2FUNC() { - // See #26987. - i := 0 // ERROR "moved to heap: i$" - j := 0 - sink, _ = leakParams(&i, &j) -} - -// The list below is all of the why-escapes messages seen building the escape analysis tests. -/* - for i in escape*go ; do echo compile $i; go build -gcflags '-l -m -m' $i >& `basename $i .go`.log ; done - grep 'from .* at ' escape*.log | sed -e 's/^.*(\([^()]*\))[^()]*$/\1/' | sort -u -*/ -// sed RE above assumes that (reason) is the last parenthesized phrase in the line, -// and that none of the reasons contains any parentheses - -/* -... arg to recursive call -address-of -appended slice... -appended to slice -appendee slice -arg to ... -arg to recursive call -array-element-equals -array literal element -assigned -assigned to top level variable -assign-pair-dot-type -assign-pair-func-call -captured by a closure -captured by called closure -dot -dot-equals -dot of pointer -fixed-array-index-of -go func arg -indirection -interface-converted -key of map put -map literal key -map literal value -non-constant size -panic -parameter to indirect call -passed-to-and-returned-from-call -passed to call[argument content escapes] -passed to call[argument escapes] -pointer literal -range-deref -receiver in indirect call -return -returned from recursive function -slice-element-equals -slice-literal-element -star-dot-equals -star-equals -struct literal element -too large for stack -value of map put -*/ - -// Expected, but not yet seen (they may be unreachable): - -/* -append-first-arg -assign-pair-mapr -assign-pair-receive -call receiver -map index -pointer literal [assign] -slice literal element -*/ diff --git a/test/escape_calls.go b/test/escape_calls.go index 53f14dff..2dbfee15 100644 --- a/test/escape_calls.go +++ b/test/escape_calls.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l -newescape=true +// errorcheck -0 -m -l // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -44,7 +44,7 @@ func walk(np **Node) int { // ERROR "leaking param content: np" } // Test for bug where func var f used prototype's escape analysis results. -func prototype(xyz []string) {} // ERROR "prototype xyz does not escape" +func prototype(xyz []string) {} // ERROR "xyz does not escape" func bar() { var got [][]string f := prototype diff --git a/test/escape_closure.go b/test/escape_closure.go index cf055d3b..3b14027f 100644 --- a/test/escape_closure.go +++ b/test/escape_closure.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l -newescape=true +// errorcheck -0 -m -l // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -38,7 +38,7 @@ func ClosureCallArgs2() { func ClosureCallArgs3() { x := 0 // ERROR "moved to heap: x" func(p *int) { // ERROR "leaking param: p" "func literal does not escape" - sink = p // ERROR "p escapes to heap" + sink = p }(&x) } @@ -53,7 +53,7 @@ func ClosureCallArgs5() { x := 0 // ERROR "moved to heap: x" // TODO(mdempsky): We get "leaking param: p" here because the new escape analysis pass // can tell that p flows directly to sink, but it's a little weird. Re-evaluate. - sink = func(p *int) *int { // ERROR "leaking param: p" "func literal does not escape" "\(func literal\)\(&x\) escapes to heap" + sink = func(p *int) *int { // ERROR "leaking param: p" "func literal does not escape" return p }(&x) } @@ -61,7 +61,7 @@ func ClosureCallArgs5() { func ClosureCallArgs6() { x := 0 // ERROR "moved to heap: x" func(p *int) { // ERROR "moved to heap: p" "func literal does not escape" - sink = &p // ERROR "&p escapes to heap" + sink = &p }(&x) } @@ -105,7 +105,7 @@ func ClosureCallArgs10() { func ClosureCallArgs11() { x := 0 // ERROR "moved to heap: x" defer func(p *int) { // ERROR "leaking param: p" "func literal does not escape" - sink = p // ERROR "p escapes to heap" + sink = p }(&x) } @@ -119,7 +119,7 @@ func ClosureCallArgs12() { func ClosureCallArgs13() { x := 0 // ERROR "moved to heap: x" defer func(p *int) { // ERROR "moved to heap: p" "func literal does not escape" - sink = &p // ERROR "&p escapes to heap" + sink = &p }(&x) } @@ -134,33 +134,33 @@ func ClosureCallArgs14() { func ClosureCallArgs15() { x := 0 // ERROR "moved to heap: x" p := &x - sink = func(p **int) *int { // ERROR "leaking param content: p" "func literal does not escape" "\(func literal\)\(&p\) escapes to heap" + sink = func(p **int) *int { // ERROR "leaking param content: p" "func literal does not escape" return *p }(&p) } -func ClosureLeak1(s string) string { // ERROR "ClosureLeak1 s does not escape" +func ClosureLeak1(s string) string { // ERROR "s does not escape" t := s + "YYYY" // ERROR "escapes to heap" - return ClosureLeak1a(t) // ERROR "ClosureLeak1 ... argument does not escape" + return ClosureLeak1a(t) // ERROR "... argument does not escape" } // See #14409 -- returning part of captured var leaks it. func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1$" - return func() string { // ERROR "ClosureLeak1a func literal does not escape" + return func() string { // ERROR "func literal does not escape" return a[0] }() } -func ClosureLeak2(s string) string { // ERROR "ClosureLeak2 s does not escape" +func ClosureLeak2(s string) string { // ERROR "s does not escape" t := s + "YYYY" // ERROR "escapes to heap" - c := ClosureLeak2a(t) // ERROR "ClosureLeak2 ... argument does not escape" + c := ClosureLeak2a(t) // ERROR "... argument does not escape" return c } func ClosureLeak2a(a ...string) string { // ERROR "leaking param content: a" - return ClosureLeak2b(func() string { // ERROR "ClosureLeak2a func literal does not escape" + return ClosureLeak2b(func() string { // ERROR "func literal does not escape" return a[0] }) } -func ClosureLeak2b(f func() string) string { // ERROR "ClosureLeak2b f does not escape" +func ClosureLeak2b(f func() string) string { // ERROR "f does not escape" return f() } diff --git a/test/escape_field.go b/test/escape_field.go index 5d5a6f36..bf1dfb18 100644 --- a/test/escape_field.go +++ b/test/escape_field.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l -newescape=true +// errorcheck -0 -m -l // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -24,7 +24,7 @@ func field0() { i := 0 // ERROR "moved to heap: i$" var x X x.p1 = &i - sink = x.p1 // ERROR "x\.p1 escapes to heap" + sink = x.p1 } func field1() { @@ -32,14 +32,14 @@ func field1() { var x X // BAD: &i should not escape x.p1 = &i - sink = x.p2 // ERROR "x\.p2 escapes to heap" + sink = x.p2 } func field3() { i := 0 // ERROR "moved to heap: i$" var x X x.p1 = &i - sink = x // ERROR "x escapes to heap" + sink = x // ERROR "x escapes to heap" } func field4() { @@ -55,12 +55,12 @@ func field5() { var x X // BAD: &i should not escape here x.a[0] = &i - sink = x.a[1] // ERROR "x\.a\[1\] escapes to heap" + sink = x.a[1] } // BAD: we are not leaking param x, only x.p2 func field6(x *X) { // ERROR "leaking param content: x$" - sink = x.p2 // ERROR "x\.p2 escapes to heap" + sink = x.p2 } func field6a() { @@ -88,7 +88,7 @@ func field8() { x := y.x var y1 Y y1.x = x - sink = y1.x.p1 // ERROR "y1\.x\.p1 escapes to heap" + sink = y1.x.p1 } func field9() { @@ -109,39 +109,39 @@ func field10() { x := y.x var y1 Y y1.x = x - sink = y1.x.p2 // ERROR "y1\.x\.p2 escapes to heap" + sink = y1.x.p2 } func field11() { - i := 0 // ERROR "moved to heap: i$" + i := 0 // ERROR "moved to heap: i$" x := X{p1: &i} - sink = x.p1 // ERROR "x\.p1 escapes to heap" + sink = x.p1 } func field12() { i := 0 // ERROR "moved to heap: i$" // BAD: &i should not escape x := X{p1: &i} - sink = x.p2 // ERROR "x\.p2 escapes to heap" + sink = x.p2 } func field13() { i := 0 // ERROR "moved to heap: i$" - x := &X{p1: &i} // ERROR "field13 &X literal does not escape$" - sink = x.p1 // ERROR "x\.p1 escapes to heap" + x := &X{p1: &i} // ERROR "&X literal 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 "field14 &X literal does not escape$" - sink = x.p2 // ERROR "x\.p2 escapes to heap" + x := &X{p1: &i} // ERROR "&X literal 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$" - sink = x // ERROR "x escapes to heap" + sink = x } func field16() { @@ -149,18 +149,18 @@ func field16() { var x X // BAD: &i should not escape x.p1 = &i - var iface interface{} = x // ERROR "field16 x does not escape" + var iface interface{} = x // ERROR "x does not escape" x1 := iface.(X) - sink = x1.p2 // ERROR "x1\.p2 escapes to heap" + sink = x1.p2 } func field17() { i := 0 // ERROR "moved to heap: i$" var x X x.p1 = &i - var iface interface{} = x // ERROR "field17 x does not escape" + var iface interface{} = x // ERROR "x does not escape" x1 := iface.(X) - sink = x1.p1 // ERROR "x1\.p1 escapes to heap" + sink = x1.p1 } func field18() { @@ -168,7 +168,7 @@ func field18() { var x X // BAD: &i should not escape x.p1 = &i - var iface interface{} = x // ERROR "field18 x does not escape" + var iface interface{} = x // ERROR "x does not escape" y, _ := iface.(Y) // Put X, but extracted Y. The cast will fail, so y is zero initialized. sink = y // ERROR "y escapes to heap" } diff --git a/test/escape_goto.go b/test/escape_goto.go new file mode 100644 index 00000000..f024a9af --- /dev/null +++ b/test/escape_goto.go @@ -0,0 +1,44 @@ +// errorcheck -0 -m -l + +// 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. + +// Test escape analysis for goto statements. + +package escape + +var x bool + +func _() { + var p *int +loop: + if x { + goto loop + } + // BAD: We should be able to recognize that there + // aren't any more "goto loop" after here. + p = new(int) // ERROR "escapes to heap" + _ = p +} + +func _() { + var p *int + if x { + loop: + goto loop + } else { + p = new(int) // ERROR "does not escape" + } + _ = p +} + +func _() { + var p *int + if x { + loop: + goto loop + } + p = new(int) // ERROR "does not escape" + _ = p +} diff --git a/test/escape_hash_maphash.go b/test/escape_hash_maphash.go new file mode 100644 index 00000000..f8dcc545 --- /dev/null +++ b/test/escape_hash_maphash.go @@ -0,0 +1,19 @@ +// errorcheck -0 -m -l + +// 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. + +// Test escape analysis for hash/maphash. + +package escape + +import ( + "hash/maphash" +) + +func f() { + var x maphash.Hash // should be stack allocatable + x.WriteString("foo") + x.Sum64() +} diff --git a/test/escape_iface.go b/test/escape_iface.go index 50c69cd5..118ed3c5 100644 --- a/test/escape_iface.go +++ b/test/escape_iface.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l -newescape=true +// errorcheck -0 -m -l // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -15,7 +15,7 @@ type M interface { } func mescapes(m M) { // ERROR "leaking param: m" - sink = m // ERROR "m escapes to heap" + sink = m } func mdoesnotescape(m M) { // ERROR "m does not escape" @@ -33,19 +33,19 @@ func efaceEscape0() { { i := 0 v := M0{&i} - var x M = v // ERROR "v does not escape" + var x M = v _ = x } { i := 0 // ERROR "moved to heap: i" v := M0{&i} - var x M = v // ERROR "v escapes to heap" - sink = x // ERROR "x escapes to heap" + var x M = v + sink = x } { i := 0 v := M0{&i} - var x M = v // ERROR "v does not escape" + var x M = v v1 := x.(M0) _ = v1 } @@ -53,27 +53,27 @@ func efaceEscape0() { i := 0 // ERROR "moved to heap: i" v := M0{&i} // BAD: v does not escape to heap here - var x M = v // ERROR "v escapes to heap" + var x M = v v1 := x.(M0) - sink = v1 // ERROR "v1 escapes to heap" + sink = v1 } { i := 0 // ERROR "moved to heap: i" v := M0{&i} // BAD: v does not escape to heap here - var x M = v // ERROR "v escapes to heap" + var x M = v x.M() } { i := 0 // ERROR "moved to heap: i" v := M0{&i} - var x M = v // ERROR "v escapes to heap" + var x M = v mescapes(x) } { i := 0 v := M0{&i} - var x M = v // ERROR "v does not escape" + var x M = v mdoesnotescape(x) } } @@ -98,7 +98,7 @@ func efaceEscape1() { i := 0 // ERROR "moved to heap: i" v := M1{&i, 0} var x M = v // ERROR "v escapes to heap" - sink = x // ERROR "x escapes to heap" + sink = x } { i := 0 @@ -110,7 +110,7 @@ func efaceEscape1() { { i := 0 // ERROR "moved to heap: i" v := M1{&i, 0} - var x M = v // ERROR "efaceEscape1 v does not escape" + var x M = v // ERROR "v does not escape" v1 := x.(M1) sink = v1 // ERROR "v1 escapes to heap" } @@ -147,19 +147,19 @@ func efaceEscape2() { { i := 0 v := &M2{&i} // ERROR "&M2 literal does not escape" - var x M = v // ERROR "v does not escape" + var x M = v _ = x } { i := 0 // ERROR "moved to heap: i" v := &M2{&i} // ERROR "&M2 literal escapes to heap" - var x M = v // ERROR "v escapes to heap" - sink = x // ERROR "x escapes to heap" + var x M = v + sink = x } { i := 0 v := &M2{&i} // ERROR "&M2 literal does not escape" - var x M = v // ERROR "v does not escape" + var x M = v v1 := x.(*M2) _ = v1 } @@ -167,44 +167,44 @@ func efaceEscape2() { i := 0 // ERROR "moved to heap: i" v := &M2{&i} // ERROR "&M2 literal escapes to heap" // BAD: v does not escape to heap here - var x M = v // ERROR "v escapes to heap" + var x M = v v1 := x.(*M2) - sink = v1 // ERROR "v1 escapes to heap" + sink = v1 } { i := 0 // ERROR "moved to heap: i" v := &M2{&i} // ERROR "&M2 literal does not escape" // BAD: v does not escape to heap here - var x M = v // ERROR "v does not escape" + var x M = v v1 := x.(*M2) - sink = *v1 // ERROR "v1 escapes to heap" + sink = *v1 } { i := 0 // ERROR "moved to heap: i" v := &M2{&i} // ERROR "&M2 literal does not escape" // BAD: v does not escape to heap here - var x M = v // ERROR "v does not escape" + var x M = v v1, ok := x.(*M2) - sink = *v1 // ERROR "v1 escapes to heap" + sink = *v1 _ = ok } { i := 0 // ERROR "moved to heap: i" v := &M2{&i} // ERROR "&M2 literal escapes to heap" // BAD: v does not escape to heap here - var x M = v // ERROR "v escapes to heap" + var x M = v x.M() } { i := 0 // ERROR "moved to heap: i" v := &M2{&i} // ERROR "&M2 literal escapes to heap" - var x M = v // ERROR "v escapes to heap" + var x M = v mescapes(x) } { i := 0 v := &M2{&i} // ERROR "&M2 literal does not escape" - var x M = v // ERROR "v does not escape" + var x M = v mdoesnotescape(x) } } @@ -220,8 +220,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{ - T1: *(x.(*T1)), // ERROR "&T2 literal escapes to heap" + return &T2{ // ERROR "&T2 literal escapes to heap" + T1: *(x.(*T1)), } } @@ -251,10 +251,10 @@ func dotTypeEscape2() { // #13805, #15796 i := 0 // ERROR "moved to heap: i" j := 0 // ERROR "moved to heap: j" var ok bool - var x interface{} = &i // ERROR "&i escapes to heap" - var y interface{} = &j // ERROR "&j escapes to heap" + var x interface{} = &i + var y interface{} = &j - sink = x.(*int) // ERROR "x.\(\*int\) escapes to heap" + sink = x.(*int) sink, *(&ok) = y.(*int) } } diff --git a/test/escape_indir.go b/test/escape_indir.go index ce21ea82..19889f25 100644 --- a/test/escape_indir.go +++ b/test/escape_indir.go @@ -54,7 +54,7 @@ func constptr1() { i := 0 // ERROR "moved to heap: i" x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap" x.p = &i - sink = x // ERROR "x escapes to heap" + sink = x } func constptr2() { @@ -127,7 +127,7 @@ func constptr11() *ConstPtr { return p } -func foo(p **int) { // ERROR "foo p does not escape" +func foo(p **int) { // ERROR "p does not escape" i := 0 // ERROR "moved to heap: i" y := p *y = &i @@ -144,7 +144,7 @@ func foo2() { f **int } x := new(int) // ERROR "moved to heap: x" "new\(int\) escapes to heap" - sink = &x // ERROR "&x escapes to heap" + sink = &x var z Z z.f = &x p := z.f diff --git a/test/escape_level.go b/test/escape_level.go index 44a23e5a..33ae5405 100644 --- a/test/escape_level.go +++ b/test/escape_level.go @@ -15,7 +15,7 @@ func level0() { p0 := &i // ERROR "moved to heap: p0" p1 := &p0 // ERROR "moved to heap: p1" p2 := &p1 // ERROR "moved to heap: p2" - sink = &p2 // ERROR "&p2 escapes to heap" + sink = &p2 } func level1() { @@ -23,7 +23,7 @@ func level1() { p0 := &i // ERROR "moved to heap: p0" p1 := &p0 // ERROR "moved to heap: p1" p2 := &p1 - sink = p2 // ERROR "p2 escapes to heap" + sink = p2 } func level2() { @@ -31,7 +31,7 @@ func level2() { p0 := &i // ERROR "moved to heap: p0" p1 := &p0 p2 := &p1 - sink = *p2 // ERROR "\*p2 escapes to heap" + sink = *p2 } func level3() { @@ -39,7 +39,7 @@ func level3() { p0 := &i p1 := &p0 p2 := &p1 - sink = **p2 // ERROR "\* \(\*p2\) escapes to heap" + sink = **p2 } func level4() { @@ -47,7 +47,7 @@ func level4() { p0 := &i // ERROR "moved to heap: p0" p1 := &p0 p2 := p1 // ERROR "moved to heap: p2" - sink = &p2 // ERROR "&p2 escapes to heap" + sink = &p2 } func level5() { @@ -55,7 +55,7 @@ func level5() { p0 := &i // ERROR "moved to heap: p0" p1 := &p0 p2 := p1 - sink = p2 // ERROR "p2 escapes to heap" + sink = p2 } func level6() { @@ -63,7 +63,7 @@ func level6() { p0 := &i p1 := &p0 p2 := p1 - sink = *p2 // ERROR "\*p2 escapes to heap" + sink = *p2 } func level7() { @@ -72,7 +72,7 @@ func level7() { p1 := &p0 // note *p1 == &i p2 := *p1 // ERROR "moved to heap: p2" - sink = &p2 // ERROR "&p2 escapes to heap" + sink = &p2 } func level8() { @@ -80,7 +80,7 @@ func level8() { p0 := &i p1 := &p0 p2 := *p1 - sink = p2 // ERROR "p2 escapes to heap" + sink = p2 } func level9() { @@ -104,5 +104,5 @@ func level11() { p0 := &i p1 := &p0 p2 := **p1 // ERROR "moved to heap: p2" - sink = &p2 // ERROR "&p2 escapes to heap" + sink = &p2 } diff --git a/test/escape_map.go b/test/escape_map.go index 9912b55a..0e9896a9 100644 --- a/test/escape_map.go +++ b/test/escape_map.go @@ -95,7 +95,7 @@ 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" - sink = m // ERROR "m escapes to heap" + sink = m } func map9() *int { diff --git a/test/escape_param.go b/test/escape_param.go index 20975567..d8fafc53 100644 --- a/test/escape_param.go +++ b/test/escape_param.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l -newescape=true +// errorcheck -0 -m -l // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -27,7 +27,7 @@ func caller0a() { func caller0b() { i := 0 // ERROR "moved to heap: i$" - sink = param0(&i) // ERROR "param0\(&i\) escapes to heap" + sink = param0(&i) } // in, in -> out, out @@ -42,7 +42,7 @@ func caller1() { } // in -> other in -func param2(p1 *int, p2 **int) { // ERROR "leaking param: p1$" "param2 p2 does not escape$" +func param2(p1 *int, p2 **int) { // ERROR "leaking param: p1$" "p2 does not escape$" *p2 = p1 } @@ -57,7 +57,7 @@ func caller2b() { i := 0 // ERROR "moved to heap: i$" var p *int param2(&i, &p) - sink = p // ERROR "p escapes to heap$" + sink = p } func paramArraySelfAssign(p *PairOfPairs) { // ERROR "p does not escape" @@ -88,27 +88,27 @@ func leakParam(x interface{}) { // ERROR "leaking param: x" func sinkAfterSelfAssignment1(box *BoxedPair) { // ERROR "leaking param content: box" box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" - sink = box.pair.p2 // ERROR "box.pair.p2 escapes to heap" + sink = box.pair.p2 } func sinkAfterSelfAssignment2(box *BoxedPair) { // ERROR "leaking param content: box" box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" - sink = box.pair // ERROR "box.pair escapes to heap" + sink = box.pair } func sinkAfterSelfAssignment3(box *BoxedPair) { // ERROR "leaking param content: box" box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" - leakParam(box.pair.p2) // ERROR "box.pair.p2 escapes to heap" + leakParam(box.pair.p2) } func sinkAfterSelfAssignment4(box *BoxedPair) { // ERROR "leaking param content: box" box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" - leakParam(box.pair) // ERROR "box.pair escapes to heap" + leakParam(box.pair) } func selfAssignmentAndUnrelated(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape" box1.pair.p1 = box1.pair.p2 // ERROR "ignoring self-assignment in box1.pair.p1 = box1.pair.p2" - leakParam(box2.pair.p2) // ERROR "box2.pair.p2 escapes to heap" + leakParam(box2.pair.p2) } func notSelfAssignment1(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape" @@ -137,7 +137,7 @@ type Pair struct { p2 *int } -func param3(p *Pair) { // ERROR "param3 p does not escape" +func param3(p *Pair) { // ERROR "p does not escape" p.p1 = p.p2 // ERROR "param3 ignoring self-assignment in p.p1 = p.p2" } @@ -158,7 +158,7 @@ func caller3b() { } // in -> rcvr -func (p *Pair) param4(i *int) { // ERROR "\(\*Pair\).param4 p does not escape$" "leaking param: i$" +func (p *Pair) param4(i *int) { // ERROR "p does not escape$" "leaking param: i$" p.p1 = i } @@ -178,7 +178,7 @@ func caller4b() { // in -> heap func param5(i *int) { // ERROR "leaking param: i$" - sink = i // ERROR "i escapes to heap$" + sink = i } func caller5() { @@ -188,7 +188,7 @@ func caller5() { // *in -> heap func param6(i ***int) { // ERROR "leaking param content: i$" - sink = *i // ERROR "\*i escapes to heap$" + sink = *i } func caller6a() { @@ -200,18 +200,18 @@ func caller6a() { // **in -> heap func param7(i ***int) { // ERROR "leaking param content: i$" - sink = **i // ERROR "\* \(\*i\) escapes to heap" + sink = **i } func caller7() { i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p$" + p := &i p2 := &p param7(&p2) } // **in -> heap -func param8(i **int) { // ERROR "param8 i does not escape$" +func param8(i **int) { // ERROR "i does not escape$" sink = **i // ERROR "\* \(\*i\) escapes to heap" } @@ -237,7 +237,7 @@ func caller9b() { i := 0 // ERROR "moved to heap: i$" p := &i // ERROR "moved to heap: p$" p2 := &p - sink = param9(&p2) // ERROR "param9\(&p2\) escapes to heap" + sink = param9(&p2) } // **in -> out @@ -256,7 +256,7 @@ func caller10b() { i := 0 // ERROR "moved to heap: i$" p := &i p2 := &p - sink = param10(&p2) // ERROR "param10\(&p2\) escapes to heap" + sink = param10(&p2) } // in escapes to heap (address of param taken and returned) @@ -273,20 +273,20 @@ func caller11a() { func caller11b() { i := 0 // ERROR "moved to heap: i$" p := &i // ERROR "moved to heap: p$" - sink = param11(&p) // ERROR "param11\(&p\) escapes to heap" + sink = param11(&p) } func caller11c() { // GOOD i := 0 // ERROR "moved to heap: i$" p := &i // ERROR "moved to heap: p" - sink = *param11(&p) // ERROR "\*param11\(&p\) escapes to heap" + sink = *param11(&p) } func caller11d() { i := 0 // ERROR "moved to heap: i$" p := &i // ERROR "moved to heap: p" p2 := &p - sink = param11(p2) // ERROR "param11\(p2\) escapes to heap" + sink = param11(p2) } // &in -> rcvr @@ -294,7 +294,7 @@ type Indir struct { p ***int } -func (r *Indir) param12(i **int) { // ERROR "\(\*Indir\).param12 r does not escape$" "moved to heap: i$" +func (r *Indir) param12(i **int) { // ERROR "r does not escape$" "moved to heap: i$" r.p = &i } @@ -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 "caller12b &Indir literal does not escape$" + r := &Indir{} // ERROR "&Indir literal does not escape$" r.param12(&p) _ = r } @@ -319,7 +319,7 @@ func caller12c() { p := &i // ERROR "moved to heap: p$" r := Indir{} r.param12(&p) - sink = r // ERROR "r escapes to heap$" + sink = r } func caller12d() { @@ -327,7 +327,7 @@ func caller12d() { p := &i // ERROR "moved to heap: p$" r := Indir{} r.param12(&p) - sink = **r.p // ERROR "\* \(\*r\.p\) escapes to heap" + sink = **r.p } // in -> value rcvr @@ -335,7 +335,7 @@ type Val struct { p **int } -func (v Val) param13(i *int) { // ERROR "Val.param13 v does not escape$" "leaking param: i$" +func (v Val) param13(i *int) { // ERROR "v does not escape$" "leaking param: i$" *v.p = i } @@ -359,7 +359,7 @@ func caller13b() { func caller13c() { i := 0 // ERROR "moved to heap: i$" var p *int - v := &Val{&p} // ERROR "caller13c &Val literal does not escape$" + v := &Val{&p} // ERROR "&Val literal does not escape$" v.param13(&i) _ = v } @@ -370,7 +370,7 @@ func caller13d() { var v Val v.p = &p v.param13(&i) - sink = v // ERROR "v escapes to heap$" + sink = v } func caller13e() { @@ -378,7 +378,7 @@ func caller13e() { var p *int // ERROR "moved to heap: p$" v := Val{&p} v.param13(&i) - sink = v // ERROR "v escapes to heap$" + sink = v } func caller13f() { @@ -386,7 +386,7 @@ func caller13f() { var p *int // ERROR "moved to heap: p$" v := &Val{&p} // ERROR "&Val literal escapes to heap$" v.param13(&i) - sink = v // ERROR "v escapes to heap$" + sink = v } func caller13g() { @@ -394,13 +394,13 @@ func caller13g() { var p *int v := Val{&p} v.param13(&i) - sink = *v.p // ERROR "\*v\.p escapes to heap" + sink = *v.p } func caller13h() { i := 0 // ERROR "moved to heap: i$" var p *int - v := &Val{&p} // ERROR "caller13h &Val literal does not escape$" + v := &Val{&p} // ERROR "&Val literal does not escape$" v.param13(&i) sink = **v.p // ERROR "\* \(\*v\.p\) escapes to heap" } @@ -420,7 +420,7 @@ func g(x *Node) *Node { // ERROR "leaking param content: x" } func h(x *Node) { // ERROR "leaking param: x" - y := &Node{x} // ERROR "h &Node literal does not escape" + y := &Node{x} // ERROR "&Node literal does not escape" Sink = g(y) f(y) } @@ -437,5 +437,5 @@ func param14a(x [4]*int) interface{} { // ERROR "leaking param: x$" // Convert to a direct interface, does not need an allocation. // So x only leaks to result. func param14b(x *int) interface{} { // ERROR "leaking param: x to result ~r1 level=0" - return x // ERROR "x escapes to heap" + return x } diff --git a/test/escape_slice.go b/test/escape_slice.go index 03053cf3..d2cdaa6a 100644 --- a/test/escape_slice.go +++ b/test/escape_slice.go @@ -18,28 +18,28 @@ var sink interface{} func slice0() { var s []*int // BAD: i should not escape - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s = append(s, &i) _ = s } func slice1() *int { var s []*int - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s = append(s, &i) return s[0] } func slice2() []*int { var s []*int - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s = append(s, &i) return s } func slice3() *int { var s []*int - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s = append(s, &i) for _, p := range s { return p @@ -48,7 +48,7 @@ func slice3() *int { } func slice4(s []*int) { // ERROR "s does not escape" - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s[0] = &i } @@ -56,14 +56,14 @@ func slice5(s []*int) { // ERROR "s does not escape" if s != nil { s = make([]*int, 10) // ERROR "make\(\[\]\*int, 10\) does not escape" } - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s[0] = &i } func slice6() { s := make([]*int, 10) // ERROR "make\(\[\]\*int, 10\) does not escape" // BAD: i should not escape - i := 0 // ERROR "moved to heap: i" + i := 0 // ERROR "moved to heap: i" s[0] = &i _ = s } @@ -93,6 +93,14 @@ func slice10() []*int { return s } +func slice11() { + i := 2 + s := make([]int, 2, 3) // ERROR "make\(\[\]int, 2, 3\) does not escape" + s = make([]int, i, 3) // ERROR "make\(\[\]int, i, 3\) does not escape" + s = make([]int, i, 1) // ERROR "make\(\[\]int, i, 1\) does not escape" + _ = s +} + 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" diff --git a/test/escape_struct_param1.go b/test/escape_struct_param1.go index 7004946e..70b36191 100644 --- a/test/escape_struct_param1.go +++ b/test/escape_struct_param1.go @@ -38,7 +38,7 @@ func tSPPi() { s := "cat" // ERROR "moved to heap: s$" ps := &s pps := &ps - pu := &U{ps, pps} // ERROR "tSPPi &U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U literal does not escape$" Ssink = pu.SPPi() } @@ -46,7 +46,7 @@ func tiSPP() { s := "cat" // ERROR "moved to heap: s$" ps := &s pps := &ps - pu := &U{ps, pps} // ERROR "tiSPP &U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U literal does not escape$" Ssink = *pu.SPP() } @@ -55,7 +55,7 @@ func tSP() { s := "cat" // ERROR "moved to heap: s$" ps := &s // ERROR "moved to heap: ps$" pps := &ps - pu := &U{ps, pps} // ERROR "tSP &U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U literal does not escape$" Ssink = pu.SP() } @@ -123,9 +123,9 @@ func tUPiSPa() { ps4 := &s4 // ERROR "moved to heap: ps4$" ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPa &U literal does not escape$" + 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 "tUPiSPa &V literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" Ssink = v.UPiSPa() // Ssink = &s3 (only &s3 really escapes) } @@ -141,9 +141,9 @@ func tUPiSPb() { ps4 := &s4 // ERROR "moved to heap: ps4$" ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPb &U literal does not escape$" + 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 "tUPiSPb &V literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" Ssink = v.UPiSPb() // Ssink = &s3 (only &s3 really escapes) } @@ -159,9 +159,9 @@ func tUPiSPc() { ps4 := &s4 // ERROR "moved to heap: ps4$" ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPc &U literal does not escape$" + 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 "tUPiSPc &V literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" Ssink = v.UPiSPc() // Ssink = &s3 (only &s3 really escapes) } @@ -177,9 +177,9 @@ func tUPiSPd() { ps4 := &s4 // ERROR "moved to heap: ps4$" ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPd &U literal does not escape$" + 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 "tUPiSPd &V literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" Ssink = v.UPiSPd() // Ssink = &s3 (only &s3 really escapes) } @@ -211,9 +211,9 @@ func tUPiSPPia() { ps4 := &s4 ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPia &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPiSPPia &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPia &V literal does not escape$" + 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$" Ssink = v.UPiSPPia() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -229,9 +229,9 @@ func tUPiSPPib() { ps4 := &s4 ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPib &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPiSPPib &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPib &V literal does not escape$" + 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$" Ssink = v.UPiSPPib() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -247,9 +247,9 @@ func tUPiSPPic() { ps4 := &s4 ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPic &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPiSPPic &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPic &V literal does not escape$" + 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$" Ssink = v.UPiSPPic() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -265,9 +265,9 @@ func tUPiSPPid() { ps4 := &s4 ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPid &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPiSPPid &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPid &V literal does not escape$" + 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$" Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -291,8 +291,8 @@ func tUPPiSPPia() { ps4 := &s4 ps6 := &s6 u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPPiSPPia &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPPiSPPia &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPPiSPPia &V literal does not escape$" + 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$" 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 5a9b2719..e42be797 100644 --- a/test/escape_struct_param2.go +++ b/test/escape_struct_param2.go @@ -38,7 +38,7 @@ func tSPPi() { s := "cat" // ERROR "moved to heap: s$" ps := &s pps := &ps - pu := &U{ps, pps} // ERROR "tSPPi &U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U literal does not escape$" Ssink = pu.SPPi() } @@ -46,7 +46,7 @@ func tiSPP() { s := "cat" // ERROR "moved to heap: s$" ps := &s pps := &ps - pu := &U{ps, pps} // ERROR "tiSPP &U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U literal does not escape$" Ssink = *pu.SPP() } @@ -55,7 +55,7 @@ func tSP() { s := "cat" // ERROR "moved to heap: s$" ps := &s // ERROR "moved to heap: ps$" pps := &ps - pu := &U{ps, pps} // ERROR "tSP &U literal does not escape$" + pu := &U{ps, pps} // ERROR "&U literal does not escape$" Ssink = pu.SP() } @@ -123,9 +123,9 @@ func tUPiSPa() { ps4 := &s4 // ERROR "moved to heap: ps4$" ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPa &U literal does not escape$" + 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 "tUPiSPa &V literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" Ssink = v.UPiSPa() // Ssink = &s3 (only &s3 really escapes) } @@ -141,9 +141,9 @@ func tUPiSPb() { ps4 := &s4 // ERROR "moved to heap: ps4$" ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPb &U literal does not escape$" + 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 "tUPiSPb &V literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" Ssink = v.UPiSPb() // Ssink = &s3 (only &s3 really escapes) } @@ -159,9 +159,9 @@ func tUPiSPc() { ps4 := &s4 // ERROR "moved to heap: ps4$" ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPc &U literal does not escape$" + 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 "tUPiSPc &V literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" Ssink = v.UPiSPc() // Ssink = &s3 (only &s3 really escapes) } @@ -177,9 +177,9 @@ func tUPiSPd() { ps4 := &s4 // ERROR "moved to heap: ps4$" ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPd &U literal does not escape$" + 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 "tUPiSPd &V literal does not escape$" + v := &V{u1, u2, &u3} // ERROR "&V literal does not escape$" Ssink = v.UPiSPd() // Ssink = &s3 (only &s3 really escapes) } @@ -211,9 +211,9 @@ func tUPiSPPia() { ps4 := &s4 ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPia &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPiSPPia &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPia &V literal does not escape$" + 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$" Ssink = v.UPiSPPia() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -229,9 +229,9 @@ func tUPiSPPib() { ps4 := &s4 ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPib &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPiSPPib &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPib &V literal does not escape$" + 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$" Ssink = v.UPiSPPib() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -247,9 +247,9 @@ func tUPiSPPic() { ps4 := &s4 ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPic &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPiSPPic &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPic &V literal does not escape$" + 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$" Ssink = v.UPiSPPic() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -265,9 +265,9 @@ func tUPiSPPid() { ps4 := &s4 ps6 := &s6 // ERROR "moved to heap: ps6$" u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPiSPPid &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPiSPPid &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPiSPPid &V literal does not escape$" + 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$" Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes) } @@ -291,8 +291,8 @@ func tUPPiSPPia() { // This test is sensitive to the level cap in function summa ps4 := &s4 ps6 := &s6 u1 := U{&s1, &ps2} - u2 := &U{&s3, &ps4} // ERROR "tUPPiSPPia &U literal does not escape$" - u3 := &U{&s5, &ps6} // ERROR "tUPPiSPPia &U literal does not escape$" - v := &V{u1, u2, &u3} // ERROR "tUPPiSPPia &V literal does not escape$" + 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$" Ssink = v.UPPiSPPia() // Ssink = *&ps6 = &s6 (only &s6 really escapes) } diff --git a/test/escape_struct_return.go b/test/escape_struct_return.go index 2b6de1c7..222ef8bc 100644 --- a/test/escape_struct_return.go +++ b/test/escape_struct_return.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l -newescape=true +// errorcheck -0 -m -l // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/escape_unsafe.go b/test/escape_unsafe.go index 16f14c07..b34beacc 100644 --- a/test/escape_unsafe.go +++ b/test/escape_unsafe.go @@ -41,12 +41,12 @@ func arithMask() unsafe.Pointer { // BAD: should be "leaking param: p to result ~r1 level=0$" func valuePointer(p *int) unsafe.Pointer { // ERROR "leaking param: p$" - return unsafe.Pointer(reflect.ValueOf(p).Pointer()) // ERROR "p escapes to heap" + return unsafe.Pointer(reflect.ValueOf(p).Pointer()) } // BAD: should be "leaking param: p to result ~r1 level=0$" func valueUnsafeAddr(p *int) unsafe.Pointer { // ERROR "leaking param: p$" - return unsafe.Pointer(reflect.ValueOf(p).Elem().UnsafeAddr()) // ERROR "p escapes to heap" + return unsafe.Pointer(reflect.ValueOf(p).Elem().UnsafeAddr()) } // (6) Conversion of a reflect.SliceHeader or reflect.StringHeader diff --git a/test/finprofiled.go b/test/finprofiled.go index 0eb801a4..ca7e3c81 100644 --- a/test/finprofiled.go +++ b/test/finprofiled.go @@ -23,7 +23,7 @@ func main() { // only for middle bytes. The finalizer resurrects that object. // As the result, all allocated memory must stay alive. const ( - N = 1 << 20 + N = 1 << 20 tinyBlockSize = 16 // runtime._TinySize ) hold := make([]*int32, 0, N) @@ -36,7 +36,7 @@ func main() { } } // Finalize as much as possible. - // Note: the sleep only increases probility of bug detection, + // Note: the sleep only increases probability of bug detection, // it cannot lead to false failure. for i := 0; i < 5; i++ { runtime.GC() diff --git a/test/fixedbugs/bug169.go b/test/fixedbugs/bug169.go index f63c2f3e..62ab7c2f 100644 --- a/test/fixedbugs/bug169.go +++ b/test/fixedbugs/bug169.go @@ -5,6 +5,6 @@ // license that can be found in the LICENSE file. package main -var x = '''; // ERROR "char" +var x = '''; // ERROR "char|rune" diff --git a/test/fixedbugs/bug195.go b/test/fixedbugs/bug195.go index 8d392bda..496c0be6 100644 --- a/test/fixedbugs/bug195.go +++ b/test/fixedbugs/bug195.go @@ -18,10 +18,10 @@ type I4 interface { // GC_ERROR "invalid recursive type" I4 // GCCGO_ERROR "interface" } -type I5 interface { +type I5 interface { // GC_ERROR "invalid recursive type" I6 // GCCGO_ERROR "interface" } -type I6 interface { // GC_ERROR "invalid recursive type" +type I6 interface { I5 // GCCGO_ERROR "interface" } diff --git a/test/fixedbugs/bug211.go b/test/fixedbugs/bug211.go deleted file mode 100644 index b1504792..00000000 --- a/test/fixedbugs/bug211.go +++ /dev/null @@ -1,14 +0,0 @@ -// errorcheck - -// Copyright 2009 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 - -type R interface { duplicate() } -type S interface { duplicate() } -type T interface { R; S } // ERROR "duplicate" - -func main() { -} diff --git a/test/fixedbugs/bug251.go b/test/fixedbugs/bug251.go index 05e111a6..706bb8d6 100644 --- a/test/fixedbugs/bug251.go +++ b/test/fixedbugs/bug251.go @@ -8,11 +8,7 @@ package main type I1 interface { // GC_ERROR "invalid recursive type" m() I2 - // TODO(mdempsky): The duplicate method error is silly - // and redundant, but tricky to prevent as it's actually - // being emitted against the underlying interface type - // literal, not I1 itself. - I2 // ERROR "loop|interface|duplicate method m" + I2 // GCCGO_ERROR "loop|interface" } type I2 interface { diff --git a/test/fixedbugs/bug302.go b/test/fixedbugs/bug302.go index c763b877..87f9d4ef 100644 --- a/test/fixedbugs/bug302.go +++ b/test/fixedbugs/bug302.go @@ -9,22 +9,34 @@ package main import ( "fmt" + "io/ioutil" "os" "os/exec" "path/filepath" ) +var tmpDir string + func main() { - run("go", "tool", "compile", filepath.Join("fixedbugs", "bug302.dir", "p.go")) + fb, err := filepath.Abs("fixedbugs") + if err == nil { + tmpDir, err = ioutil.TempDir("", "bug302") + } + if err != nil { + fmt.Println(err) + os.Exit(1) + } + defer os.RemoveAll(tmpDir) + + run("go", "tool", "compile", filepath.Join(fb, "bug302.dir", "p.go")) run("go", "tool", "pack", "grc", "pp.a", "p.o") - run("go", "tool", "compile", "-I", ".", filepath.Join("fixedbugs", "bug302.dir", "main.go")) - os.Remove("p.o") - os.Remove("pp.a") - os.Remove("main.o") + run("go", "tool", "compile", "-I", ".", filepath.Join(fb, "bug302.dir", "main.go")) } func run(cmd string, args ...string) { - out, err := exec.Command(cmd, args...).CombinedOutput() + c := exec.Command(cmd, args...) + c.Dir = tmpDir + out, err := c.CombinedOutput() if err != nil { fmt.Println(string(out)) fmt.Println(err) diff --git a/test/fixedbugs/bug369.go b/test/fixedbugs/bug369.go index e2a11477..9316f7aa 100644 --- a/test/fixedbugs/bug369.go +++ b/test/fixedbugs/bug369.go @@ -11,6 +11,7 @@ package main import ( "fmt" + "io/ioutil" "os" "os/exec" "path/filepath" @@ -20,16 +21,19 @@ func main() { err := os.Chdir(filepath.Join(".", "fixedbugs", "bug369.dir")) check(err) - run("go", "tool", "compile", "-N", "-o", "slow.o", "pkg.go") - run("go", "tool", "compile", "-o", "fast.o", "pkg.go") - run("go", "tool", "compile", "-o", "main.o", "main.go") - run("go", "tool", "link", "-o", "a.exe", "main.o") - run("." + string(filepath.Separator) + "a.exe") + tmpDir, err := ioutil.TempDir("", "bug369") + check(err) + defer os.RemoveAll(tmpDir) + + tmp := func(name string) string { + return filepath.Join(tmpDir, name) + } - os.Remove("slow.o") - os.Remove("fast.o") - os.Remove("main.o") - os.Remove("a.exe") + run("go", "tool", "compile", "-N", "-o", tmp("slow.o"), "pkg.go") + run("go", "tool", "compile", "-o", tmp("fast.o"), "pkg.go") + run("go", "tool", "compile", "-D", tmpDir, "-o", tmp("main.o"), "main.go") + run("go", "tool", "link", "-o", tmp("a.exe"), tmp("main.o")) + run(tmp("a.exe")) } func run(name string, args ...string) { diff --git a/test/fixedbugs/bug373.go b/test/fixedbugs/bug373.go index aa0f5d1e..6b7a3120 100644 --- a/test/fixedbugs/bug373.go +++ b/test/fixedbugs/bug373.go @@ -9,7 +9,7 @@ package foo func f(x interface{}) { - switch t := x.(type) { // ERROR "declared and not used" + switch t := x.(type) { // ERROR "declared but not used" case int: } } diff --git a/test/fixedbugs/bug507.dir/a.go b/test/fixedbugs/bug507.dir/a.go new file mode 100644 index 00000000..0929adcf --- /dev/null +++ b/test/fixedbugs/bug507.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 + +type I interface { + M() +} + +type S struct { + I I +} diff --git a/test/fixedbugs/bug507.dir/b.go b/test/fixedbugs/bug507.dir/b.go new file mode 100644 index 00000000..bddce2dd --- /dev/null +++ b/test/fixedbugs/bug507.dir/b.go @@ -0,0 +1,9 @@ +// 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" + +var V2 I diff --git a/test/fixedbugs/bug507.dir/c.go b/test/fixedbugs/bug507.dir/c.go new file mode 100644 index 00000000..e67f0fd7 --- /dev/null +++ b/test/fixedbugs/bug507.dir/c.go @@ -0,0 +1,9 @@ +// 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" + +var V1 = a.S{I: nil} diff --git a/test/fixedbugs/bug507.go b/test/fixedbugs/bug507.go new file mode 100644 index 00000000..2d7aa597 --- /dev/null +++ b/test/fixedbugs/bug507.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. + +// Gccgo mishandled a combination of normal import and dot import. + +package ignored diff --git a/test/fixedbugs/bug508.go b/test/fixedbugs/bug508.go new file mode 100644 index 00000000..69b1adaf --- /dev/null +++ b/test/fixedbugs/bug508.go @@ -0,0 +1,14 @@ +// 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. + +// Gccgo mishandles composite literals of map with type bool. + +package p + +var M = map[bool]uint8{ + false: 0, + true: 1, +} diff --git a/test/fixedbugs/issue10607.go b/test/fixedbugs/issue10607.go index 8831547d..6f4717d8 100644 --- a/test/fixedbugs/issue10607.go +++ b/test/fixedbugs/issue10607.go @@ -1,4 +1,4 @@ -// +build linux,!ppc64 +// +build linux,!ppc64,!riscv64 // run // Copyright 2015 The Go Authors. All rights reserved. @@ -8,6 +8,9 @@ // Test that a -B option is passed through when using both internal // and external linking mode. +// TODO(jsing): Re-enable on riscv64 when it has support for external +// linking - see golang.org/issue/36739 + package main import ( diff --git a/test/fixedbugs/issue12006.go b/test/fixedbugs/issue12006.go index adbbb28b..c44f2e55 100644 --- a/test/fixedbugs/issue12006.go +++ b/test/fixedbugs/issue12006.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l -newescape=true +// errorcheck -0 -m -l // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -8,7 +8,7 @@ package foo -func FooN(vals ...*int) (s int) { // ERROR "FooN vals does not escape" +func FooN(vals ...*int) (s int) { // ERROR "vals does not escape" for _, v := range vals { s += *v } @@ -37,14 +37,14 @@ func FooNz(vals ...*int) (s int) { // ERROR "leaking param: vals" func TFooN() { for i := 0; i < 1000; i++ { var i, j int - FooN(&i, &j) // ERROR "TFooN ... argument does not escape" + FooN(&i, &j) // ERROR "... argument does not escape" } } func TFooNx() { for i := 0; i < 1000; i++ { var i, j, k int // ERROR "moved to heap: i" "moved to heap: j" "moved to heap: k" - FooNx(&k, &i, &j) // ERROR "TFooNx ... argument does not escape" + FooNx(&k, &i, &j) // ERROR "... argument does not escape" } } @@ -84,7 +84,7 @@ func TFooI() { a := int32(1) // ERROR "moved to heap: a" b := "cat" c := &a - FooI(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooI ... argument does not escape" + FooI(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "... argument does not escape" } func FooJ(args ...interface{}) *int32 { // ERROR "leaking param: args to result ~r1 level=1" @@ -108,14 +108,14 @@ func TFooJ1() { a := int32(1) b := "cat" c := &a - FooJ(a, b, c) // ERROR "TFooJ1 a does not escape" "TFooJ1 b does not escape" "TFooJ1 c does not escape" "TFooJ1 ... argument does not escape" + FooJ(a, b, c) // ERROR "a does not escape" "b does not escape" "... argument does not escape" } func TFooJ2() { a := int32(1) // ERROR "moved to heap: a" b := "cat" c := &a - isink = FooJ(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooJ2 ... argument does not escape" + isink = FooJ(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "... argument does not escape" } type fakeSlice struct { @@ -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" "c escapes to heap" "TFooK2 &\[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 {} literal 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" "c escapes to heap" "TFooL2 \[\]interface {} literal does not escape" + s := []interface{}{a, b, c} // ERROR "a escapes to heap" "b escapes to heap" "\[\]interface {} literal does not escape" isink = FooL(s) } diff --git a/test/fixedbugs/issue12588.go b/test/fixedbugs/issue12588.go index f99807b9..950ef36e 100644 --- a/test/fixedbugs/issue12588.go +++ b/test/fixedbugs/issue12588.go @@ -26,7 +26,7 @@ func f(a A) int { return 0 } -func g(a *A) int { // ERROR "g a does not escape" +func g(a *A) int { // ERROR "a does not escape" for i, x := range &a.b { if x != 0 { return 64*i + int(x) diff --git a/test/fixedbugs/issue13365.go b/test/fixedbugs/issue13365.go index 379f9b65..4bd103e3 100644 --- a/test/fixedbugs/issue13365.go +++ b/test/fixedbugs/issue13365.go @@ -19,7 +19,7 @@ func main() { _ = [10]int{100: 0} // ERROR "array index 100 out of bounds" _ = [...]int{100: 0} - _ = []int{t} // ERROR "cannot use .* as type int in array or slice literal" - _ = [10]int{t} // ERROR "cannot use .* as type int in array or slice literal" - _ = [...]int{t} // ERROR "cannot use .* as type int in array or slice literal" + _ = []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" } diff --git a/test/fixedbugs/issue13799.go b/test/fixedbugs/issue13799.go index b9bf49ca..5c574947 100644 --- a/test/fixedbugs/issue13799.go +++ b/test/fixedbugs/issue13799.go @@ -20,7 +20,7 @@ func main() { // (sometimes it takes 1 time, sometimes it takes ~4,000+). for iter := 0; ; iter++ { if iter%50 == 0 { - fmt.Println(iter) // ERROR "iter escapes to heap$" "main ... argument does not escape$" + fmt.Println(iter) // ERROR "iter escapes to heap$" "... argument does not escape$" } test1(iter) test2(iter) @@ -60,20 +60,20 @@ func test1(iter int) { } if len(m) != maxI { - panic(fmt.Sprintf("iter %d: maxI = %d, len(m) = %d", iter, maxI, len(m))) // ERROR "iter escapes to heap$" "len\(m\) escapes to heap$" "maxI escapes to heap$" "test1 ... argument does not escape$" + panic(fmt.Sprintf("iter %d: maxI = %d, len(m) = %d", iter, maxI, len(m))) // ERROR "iter escapes to heap$" "len\(m\) escapes to heap$" "maxI escapes to heap$" "... argument does not escape$" } } func test2(iter int) { const maxI = 500 - m := make(map[int][]int) // ERROR "test2 make\(map\[int\]\[\]int\) does not escape$" + m := make(map[int][]int) // ERROR "make\(map\[int\]\[\]int\) does not escape$" // var fn func() for i := 0; i < maxI; i++ { var fn func() // this makes it work, because fn stays off heap j := 0 - fn = func() { // ERROR "test2 func literal does not escape$" + fn = func() { // ERROR "func literal does not escape$" m[i] = append(m[i], 0) if j < 25 { j++ @@ -84,7 +84,7 @@ func test2(iter int) { } if len(m) != maxI { - panic(fmt.Sprintf("iter %d: maxI = %d, len(m) = %d", iter, maxI, len(m))) // ERROR "iter escapes to heap$" "len\(m\) escapes to heap$" "maxI escapes to heap$" "test2 ... argument does not escape$" + panic(fmt.Sprintf("iter %d: maxI = %d, len(m) = %d", iter, maxI, len(m))) // ERROR "iter escapes to heap$" "len\(m\) escapes to heap$" "maxI escapes to heap$" "... argument does not escape$" } } @@ -110,7 +110,7 @@ func test3(iter int) { } if *m != maxI { - panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "test3 ... argument does not escape$" + panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "... argument does not escape$" } } @@ -124,7 +124,7 @@ func test4(iter int) { for i := 0; i < maxI; i++ { var fn func() // this makes it work, because fn stays off heap j := 0 - fn = func() { // ERROR "test4 func literal does not escape$" + fn = func() { // ERROR "func literal does not escape$" if j < 100 { j++ fn() @@ -136,7 +136,7 @@ func test4(iter int) { } if *m != maxI { - panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "test4 ... argument does not escape$" + panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "... argument does not escape$" } } @@ -144,7 +144,7 @@ type str struct { m *int } -func recur1(j int, s *str) { // ERROR "recur1 s does not escape" +func recur1(j int, s *str) { // ERROR "s does not escape" if j < 100 { j++ recur1(j, s) @@ -167,7 +167,7 @@ func test5(iter int) { } if *m != maxI { - panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "test5 ... argument does not escape$" + panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "... argument does not escape$" } } @@ -185,6 +185,6 @@ func test6(iter int) { } if *m != maxI { - panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "test6 ... argument does not escape$" + panic(fmt.Sprintf("iter %d: maxI = %d, *m = %d", iter, maxI, *m)) // ERROR "\*m escapes to heap$" "iter escapes to heap$" "maxI escapes to heap$" "... argument does not escape$" } } diff --git a/test/fixedbugs/issue14636.go b/test/fixedbugs/issue14636.go index 6b342e40..6797046e 100644 --- a/test/fixedbugs/issue14636.go +++ b/test/fixedbugs/issue14636.go @@ -1,4 +1,4 @@ -// +build !nacl,!js,!android,!darwin darwin,!arm +// +build !nacl,!js,!android // run // Copyright 2016 The Go Authors. All rights reserved. diff --git a/test/fixedbugs/issue14999.go b/test/fixedbugs/issue14999.go index 6ce768e2..b648441f 100644 --- a/test/fixedbugs/issue14999.go +++ b/test/fixedbugs/issue14999.go @@ -7,11 +7,11 @@ package p func f(x int) func(int) int { - return func(y int) int { return x + y } // ERROR "heap-allocated closure, not allowed in runtime." + return func(y int) int { return x + y } // ERROR "heap-allocated closure, not allowed in runtime" } -func g(x int) func(int) int { // ERROR "x escapes to heap, not allowed in runtime." - return func(y int) int { // ERROR "heap-allocated closure, not allowed in runtime." +func g(x int) func(int) int { // ERROR "x escapes to heap, not allowed in runtime" + return func(y int) int { // ERROR "heap-allocated closure, not allowed in runtime" x += y return x + y } diff --git a/test/fixedbugs/issue15611.go b/test/fixedbugs/issue15611.go index 6a627d9b..36344754 100644 --- a/test/fixedbugs/issue15611.go +++ b/test/fixedbugs/issue15611.go @@ -8,13 +8,13 @@ package p // These error messages are for the invalid literals on lines 19 and 20: -// ERROR "newline in character literal" -// ERROR "invalid character literal \(missing closing '\)" +// ERROR "newline in character literal|newline in rune literal" +// ERROR "invalid character literal \(missing closing '\)|rune literal not terminated" const ( - _ = '' // ERROR "empty character literal or unescaped ' in character literal" + _ = '' // ERROR "empty character literal or unescaped ' in character literal|empty rune literal" _ = 'f' - _ = 'foo' // ERROR "invalid character literal \(more than one character\)" + _ = 'foo' // ERROR "invalid character literal \(more than one character\)|more than one character in rune literal" //line issue15611.go:11 _ = ' _ = '
\ No newline at end of file diff --git a/test/fixedbugs/issue15992.go b/test/fixedbugs/issue15992.go index 957bb89f..cda5527c 100644 --- a/test/fixedbugs/issue15992.go +++ b/test/fixedbugs/issue15992.go @@ -28,7 +28,7 @@ func main() { fmt.Println(n, a) b := []byte{1, 2, 3} - n = copy(f(b)) + n = copy(g(b)) fmt.Println(n, b) m := map[int]int{0: 0} diff --git a/test/fixedbugs/issue17318.go b/test/fixedbugs/issue17318.go index f8755175..21df729f 100644 --- a/test/fixedbugs/issue17318.go +++ b/test/fixedbugs/issue17318.go @@ -1,4 +1,4 @@ -// errorcheck -0 -N -m -l -newescape=true +// errorcheck -0 -N -m -l // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -22,12 +22,12 @@ type closure func(i, j int) ent type ent int func (e ent) String() string { - return fmt.Sprintf("%d", int(e)) // ERROR "ent.String ... argument does not escape$" "int\(e\) escapes to heap$" + return fmt.Sprintf("%d", int(e)) // ERROR "... argument does not escape$" "int\(e\) escapes to heap$" } //go:noinline -func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "foo ops does not escape" - enqueue := func(i int) fmt.Stringer { // ERROR "foo func literal does not escape" +func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "ops does not escape" + enqueue := func(i int) fmt.Stringer { // ERROR "func literal does not escape" return ops(i, j) // ERROR "ops\(i, j\) escapes to heap$" } err = enqueue(4) @@ -39,9 +39,9 @@ func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "foo ops does not esc func main() { // 3 identical functions, to get different escape behavior. - f := func(i, j int) ent { // ERROR "main func literal does not escape" + f := func(i, j int) ent { // ERROR "func literal does not escape" return ent(i + j) } i := foo(f, 3).(ent) - fmt.Printf("foo(f,3)=%d\n", int(i)) // ERROR "int\(i\) escapes to heap$" "main ... argument does not escape$" + fmt.Printf("foo(f,3)=%d\n", int(i)) // ERROR "int\(i\) escapes to heap$" "... argument does not escape$" } diff --git a/test/fixedbugs/issue17645.go b/test/fixedbugs/issue17645.go index ed92c54c..af785eae 100644 --- a/test/fixedbugs/issue17645.go +++ b/test/fixedbugs/issue17645.go @@ -12,6 +12,5 @@ type Foo struct { func main() { var s []int - var _ string = append(s, Foo{""}) // ERROR "cannot use .. \(type 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 literal \(type Foo\) as type int in append" "cannot use append\(s\, Foo literal\) \(type \[\]int\) as type string in assignment" } - diff --git a/test/fixedbugs/issue18915.go b/test/fixedbugs/issue18915.go index a432bbc1..66e31e25 100644 --- a/test/fixedbugs/issue18915.go +++ b/test/fixedbugs/issue18915.go @@ -10,12 +10,12 @@ package p func _() { - if a := 10 { // ERROR "a := 10 used as value" + if a := 10 { // ERROR "cannot use a := 10 as value" } - for b := 10 { // ERROR "b := 10 used as value" + for b := 10 { // ERROR "cannot use b := 10 as value" } - switch c := 10 { // ERROR "c := 10 used as value" + switch c := 10 { // ERROR "cannot use c := 10 as value" } } diff --git a/test/fixedbugs/issue20185.go b/test/fixedbugs/issue20185.go index 00c23f64..2cbb143e 100644 --- a/test/fixedbugs/issue20185.go +++ b/test/fixedbugs/issue20185.go @@ -19,7 +19,7 @@ func F() { const x = 1 func G() { - switch t := x.(type) { // ERROR "cannot type switch on non-interface value x \(type untyped number\)" + switch t := x.(type) { // ERROR "cannot type switch on non-interface value x \(type untyped int\)" default: } } diff --git a/test/fixedbugs/issue21317.go b/test/fixedbugs/issue21317.go index 530694af..ee1bbf81 100644 --- a/test/fixedbugs/issue21317.go +++ b/test/fixedbugs/issue21317.go @@ -48,8 +48,8 @@ func main() { log.Fatalf("expected cmd/compile to fail") } wantErrs := []string{ - "7:9: n declared and not used", - "7:12: err declared and not used", + "7:9: n declared but not used", + "7:12: err declared but not used", } outStr := string(out) for _, want := range wantErrs { diff --git a/test/fixedbugs/issue21576.go b/test/fixedbugs/issue21576.go new file mode 100644 index 00000000..b7a32f07 --- /dev/null +++ b/test/fixedbugs/issue21576.go @@ -0,0 +1,62 @@ +// +build !nacl,!js +// run + +// 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. +// +// Ensure that deadlock detection can still +// run even with an import of "_ os/signal". + +package main + +import ( + "bytes" + "context" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "time" +) + +const prog = ` +package main + +import _ "os/signal" + +func main() { + c := make(chan int) + c <- 1 +} +` + +func main() { + dir, err := ioutil.TempDir("", "21576") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + + file := filepath.Join(dir, "main.go") + if err := ioutil.WriteFile(file, []byte(prog), 0655); err != nil { + log.Fatalf("Write error %v", err) + } + + // Using a timeout of 1 minute in case other factors might slow + // down the start of "go run". See https://golang.org/issue/34836. + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + cmd := exec.CommandContext(ctx, "go", "run", file) + output, err := cmd.CombinedOutput() + if err == nil { + log.Fatalf("Passed, expected an error") + } + + want := []byte("fatal error: all goroutines are asleep - deadlock!") + if !bytes.Contains(output, want) { + log.Fatalf("Unmatched error message %q:\nin\n%s\nError: %v", want, output, err) + } +} diff --git a/test/fixedbugs/issue21709.go b/test/fixedbugs/issue21709.go index 6e7f1d5b..cc5896ab 100644 --- a/test/fixedbugs/issue21709.go +++ b/test/fixedbugs/issue21709.go @@ -10,14 +10,14 @@ package p type S struct{} -func (s *S) Inc() {} // ERROR "\(\*S\).Inc s does not escape" +func (s *S) Inc() {} // ERROR "s does not escape" var N int func F1() { - var s S // ERROR "moved to heap: s" + var s S for i := 0; i < N; i++ { - fs := []func(){ // ERROR "F1 \[\]func\(\) literal does not escape" - s.Inc, // ERROR "F1 s.Inc does not escape" + fs := []func(){ // ERROR "\[\]func\(\) literal does not escape" + s.Inc, // ERROR "s.Inc does not escape" } for _, f := range fs { f() @@ -26,10 +26,10 @@ func F1() { } func F2() { - var s S // ERROR "moved to heap: s" + var s S for i := 0; i < N; i++ { - for _, f := range []func(){ // ERROR "F2 \[\]func\(\) literal does not escape" - s.Inc, // ERROR "F2 s.Inc does not escape" + for _, f := range []func(){ // ERROR "\[\]func\(\) literal does not escape" + s.Inc, // ERROR "s.Inc does not escape" } { f() } diff --git a/test/fixedbugs/issue21934.go b/test/fixedbugs/issue21934.go new file mode 100644 index 00000000..e9a430f1 --- /dev/null +++ b/test/fixedbugs/issue21934.go @@ -0,0 +1,26 @@ +// errorcheck + +// 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. + +// selector expression resolves incorrectly for defined +// pointer types. + +package main + +type E struct{ f int } +type T struct{ E } + +func (*T) f() int { return 0 } + +type P *T +type PP **T + +func main() { + var x P + _ = x.f // ERROR "x\.f undefined \(type P has no field or method f\)" + + var y PP + _ = y.f // ERROR "y\.f undefined \(type PP has no field or method f\)" +} diff --git a/test/fixedbugs/issue21979.go b/test/fixedbugs/issue21979.go new file mode 100644 index 00000000..1c02f574 --- /dev/null +++ b/test/fixedbugs/issue21979.go @@ -0,0 +1,46 @@ +// errorcheck + +// 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. + +package p + +func f() { + _ = bool("") // ERROR "cannot convert .. \(type untyped string\) to type bool" + _ = bool(1) // ERROR "cannot convert 1 \(type untyped int\) to type bool" + _ = bool(1.0) // ERROR "cannot convert 1 \(type untyped float\) to type bool" + _ = bool(-4 + 2i) // ERROR "cannot convert -4 \+ 2i \(type untyped complex\) to type bool" + + _ = string(true) // ERROR "cannot convert true \(type untyped bool\) to type string" + _ = string(-1) + _ = string(1.0) // ERROR "cannot convert 1 \(type untyped float\) to type string" + _ = string(-4 + 2i) // ERROR "cannot convert -4 \+ 2i \(type untyped complex\) to type string" + + _ = int("") // ERROR "cannot convert .. \(type untyped string\) to type int" + _ = int(true) // ERROR "cannot convert true \(type untyped bool\) to type int" + _ = int(-1) + _ = int(1) + _ = int(1.0) + _ = int(-4 + 2i) // ERROR "truncated to integer" + + _ = uint("") // ERROR "cannot convert .. \(type untyped string\) to type uint" + _ = uint(true) // ERROR "cannot convert true \(type untyped bool\) to type uint" + _ = uint(-1) // ERROR "constant -1 overflows uint" + _ = uint(1) + _ = uint(1.0) + _ = uint(-4 + 2i) // ERROR "constant -4 overflows uint" "truncated to integer" + + _ = float64("") // ERROR "cannot convert .. \(type untyped string\) to type float64" + _ = float64(true) // ERROR "cannot convert true \(type untyped bool\) to type float64" + _ = float64(-1) + _ = float64(1) + _ = float64(1.0) + _ = float64(-4 + 2i) // ERROR "truncated to real" + + _ = complex128("") // ERROR "cannot convert .. \(type untyped string\) to type complex128" + _ = complex128(true) // ERROR "cannot convert true \(type untyped bool\) to type complex128" + _ = complex128(-1) + _ = complex128(1) + _ = complex128(1.0) +} diff --git a/test/fixedbugs/issue22344.go b/test/fixedbugs/issue22344.go new file mode 100644 index 00000000..9f2a6e86 --- /dev/null +++ b/test/fixedbugs/issue22344.go @@ -0,0 +1,83 @@ +// compile + +// 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. + +// Test iota inside a function in a ConstSpec is accepted +package main + +import ( + "unsafe" +) + +// iotas are usable inside closures in constant declarations (#22345) +const ( + _ = iota + _ = len([iota]byte{}) + _ = unsafe.Sizeof(iota) + _ = unsafe.Sizeof(func() { _ = iota }) + _ = unsafe.Sizeof(func() { var _ = iota }) + _ = unsafe.Sizeof(func() { const _ = iota }) + _ = unsafe.Sizeof(func() { type _ [iota]byte }) + _ = unsafe.Sizeof(func() { func() int { return iota }() }) +) + +// verify inner and outer const declarations have distinct iotas +const ( + zero = iota + one = iota + _ = unsafe.Sizeof(func() { + var x [iota]int // [2]int + var y [iota]int // [2]int + const ( + Zero = iota + One + Two + _ = unsafe.Sizeof([iota - 1]int{} == x) // assert types are equal + _ = unsafe.Sizeof([iota - 2]int{} == y) // assert types are equal + _ = unsafe.Sizeof([Two]int{} == x) // assert types are equal + ) + var z [iota]int // [2]int + _ = unsafe.Sizeof([2]int{} == z) // assert types are equal + }) + three = iota // the sequence continues +) + +var _ [three]int = [3]int{} // assert 'three' has correct value + +func main() { + + const ( + _ = iota + _ = len([iota]byte{}) + _ = unsafe.Sizeof(iota) + _ = unsafe.Sizeof(func() { _ = iota }) + _ = unsafe.Sizeof(func() { var _ = iota }) + _ = unsafe.Sizeof(func() { const _ = iota }) + _ = unsafe.Sizeof(func() { type _ [iota]byte }) + _ = unsafe.Sizeof(func() { func() int { return iota }() }) + ) + + const ( + zero = iota + one = iota + _ = unsafe.Sizeof(func() { + var x [iota]int // [2]int + var y [iota]int // [2]int + const ( + Zero = iota + One + Two + _ = unsafe.Sizeof([iota - 1]int{} == x) // assert types are equal + _ = unsafe.Sizeof([iota - 2]int{} == y) // assert types are equal + _ = unsafe.Sizeof([Two]int{} == x) // assert types are equal + ) + var z [iota]int // [2]int + _ = unsafe.Sizeof([2]int{} == z) // assert types are equal + }) + three = iota // the sequence continues + ) + + var _ [three]int = [3]int{} // assert 'three' has correct value +} diff --git a/test/fixedbugs/issue23116.go b/test/fixedbugs/issue23116.go index 1737fee2..b4b36d4b 100644 --- a/test/fixedbugs/issue23116.go +++ b/test/fixedbugs/issue23116.go @@ -10,6 +10,6 @@ func f(x interface{}) { switch x.(type) { } - switch t := x.(type) { // ERROR "declared and not used" + switch t := x.(type) { // ERROR "declared but not used" } } diff --git a/test/fixedbugs/issue24339.go b/test/fixedbugs/issue24339.go index 0670becd..502c575e 100644 --- a/test/fixedbugs/issue24339.go +++ b/test/fixedbugs/issue24339.go @@ -6,7 +6,7 @@ package p -// Use a diffent line number for each token so we can +// Use a different line number for each token so we can // check that the error message appears at the correct // position. var _ = struct{}{ /*line :20:1*/foo /*line :21:1*/: /*line :22:1*/0 } diff --git a/test/fixedbugs/issue24651a.go b/test/fixedbugs/issue24651a.go index b12b0cce..6c7bf309 100644 --- a/test/fixedbugs/issue24651a.go +++ b/test/fixedbugs/issue24651a.go @@ -12,7 +12,7 @@ func Foo(x int) int { // ERROR "cannot inline Foo: marked go:norace with -race c return x * (x + 1) * (x + 2) } -func Bar(x int) int { // ERROR "can inline Bar as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" +func Bar(x int) int { // ERROR "can inline Bar with cost .* as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" return x * (x + 1) * (x + 2) } diff --git a/test/fixedbugs/issue24651b.go b/test/fixedbugs/issue24651b.go index 2420f61f..aa88a678 100644 --- a/test/fixedbugs/issue24651b.go +++ b/test/fixedbugs/issue24651b.go @@ -7,11 +7,11 @@ package main //go:norace -func Foo(x int) int { // ERROR "can inline Foo as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" +func Foo(x int) int { // ERROR "can inline Foo with cost .* as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" return x * (x + 1) * (x + 2) } -func Bar(x int) int { // ERROR "can inline Bar as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" +func Bar(x int) int { // ERROR "can inline Bar with cost .* as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" return x * (x + 1) * (x + 2) } diff --git a/test/fixedbugs/issue25727.go b/test/fixedbugs/issue25727.go index 9b7c804a..da7c94cc 100644 --- a/test/fixedbugs/issue25727.go +++ b/test/fixedbugs/issue25727.go @@ -9,13 +9,13 @@ package main import "net/http" var s = http.Server{} -var _ = s.doneChan // ERROR "s.doneChan undefined .cannot refer to unexported field or method doneChan.$" -var _ = s.DoneChan // ERROR "s.DoneChan undefined .type http.Server has no field or method DoneChan.$" +var _ = s.doneChan // ERROR "s.doneChan undefined .cannot refer to unexported field or method doneChan.$" +var _ = s.DoneChan // ERROR "s.DoneChan undefined .type http.Server has no field or method DoneChan.$" var _ = http.Server{tlsConfig: nil} // ERROR "unknown field 'tlsConfig' in struct literal.+ .but does have TLSConfig.$" -var _ = http.Server{DoneChan: nil} // ERROR "unknown field 'DoneChan' in struct literal of type http.Server$" +var _ = http.Server{DoneChan: nil} // ERROR "unknown field 'DoneChan' in struct literal of type http.Server$" type foo struct { - bar int + bar int } var _ = &foo{bAr: 10} // ERROR "unknown field 'bAr' in struct literal.+ .but does have bar.$" diff --git a/test/fixedbugs/issue27557.go b/test/fixedbugs/issue27557.go new file mode 100644 index 00000000..e35ab5a1 --- /dev/null +++ b/test/fixedbugs/issue27557.go @@ -0,0 +1,41 @@ +// errorcheck -0 -l -m + +// 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. + +package p + +var sink interface{} + +func _() { + var t T + f := t.noescape // ERROR "t.noescape does not escape" + f() +} + +func _() { + var t T // ERROR "moved to heap" + f := t.escape // ERROR "t.escape does not escape" + f() +} + +func _() { + var t T // ERROR "moved to heap" + f := t.returns // ERROR "t.returns does not escape" + sink = f() +} + +type T struct{} + +func (t *T) noescape() {} // ERROR "t does not escape" +func (t *T) escape() { sink = t } // ERROR "leaking param: t$" +func (t *T) returns() *T { return t } // ERROR "leaking param: t to result ~r0 level=0" + +func (t *T) recursive() { // ERROR "leaking param: t$" + sink = t + + var t2 T // ERROR "moved to heap" + f := t2.recursive // ERROR "t2.recursive does not escape" + f() +} diff --git a/test/fixedbugs/issue27718.go b/test/fixedbugs/issue27718.go index f7794182..ff616fb0 100644 --- a/test/fixedbugs/issue27718.go +++ b/test/fixedbugs/issue27718.go @@ -37,6 +37,20 @@ func testSub64() { } //go:noinline +func neg64(x float64) float64 { + return -x +} + +func testNeg64() { + var zero float64 + inf := 1.0 / zero + negZero := -1 / inf + if 1/neg64(negZero) != inf { + panic("-negZero != posZero (64 bit)") + } +} + +//go:noinline func add32(x float32) float32 { return x + 0 } @@ -64,9 +78,25 @@ func testSub32() { } } +//go:noinline +func neg32(x float32) float32 { + return -x +} + +func testNeg32() { + var zero float32 + inf := 1.0 / zero + negZero := -1 / inf + if 1/neg32(negZero) != inf { + panic("-negZero != posZero (32 bit)") + } +} + func main() { testAdd64() testSub64() + testNeg64() testAdd32() testSub32() + testNeg32() } diff --git a/test/fixedbugs/issue27732a.go b/test/fixedbugs/issue27732a.go index 41b62a6d..2d0198da 100644 --- a/test/fixedbugs/issue27732a.go +++ b/test/fixedbugs/issue27732a.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -l -smallframes -newescape=true +// errorcheck -0 -m -l -smallframes // Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/fixedbugs/issue29312.go b/test/fixedbugs/issue29312.go new file mode 100644 index 00000000..4293e010 --- /dev/null +++ b/test/fixedbugs/issue29312.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. + +// This test is not for a fix of 29312 proper, but for the patch that +// makes sure we at least don't have a security hole because of 29312. + +// This code generates lots of types. The binary should contain +// a runtime.slicetype for each of the following 253 types: +// +// []*pwn +// [][]*pwn +// ... +// [][]...[][]*pwn - 249 total "[]" +// [][]...[][][]*pwn - 250 total "[]" +// [][]...[][][][]*pwn - 251 total "[]" +// [][]...[][][][][]*pwn - 252 total "[]" +// [][]...[][][][][][]*pwn - 253 total "[]" +// +// The type names for these types are as follows. Because we truncate +// the name at depth 250, the last few names are all identical: +// +// type.[]*"".pwn +// type.[][]*"".pwn +// ... +// type.[][]...[][]*pwn - 249 total "[]" +// type.[][]...[][][]*<...> - 250 total "[]" +// type.[][]...[][][][]<...> - 251 total "[]" +// type.[][]...[][][][]<...> - 252 total "[]" (but only 251 "[]" in the name) +// type.[][]...[][][][]<...> - 253 total "[]" (but only 251 "[]" in the name) +// +// Because the names of the last 3 types are all identical, the +// compiler will generate only a single runtime.slicetype data +// structure for all 3 underlying types. It turns out the compiler +// generates just the 251-entry one. There aren't any +// runtime.slicetypes generated for the final two types. +// +// The compiler passes type.[]...[]<...> (251 total "[]") to +// fmt.Sprintf (instead of the correct 253 one). But the data +// structure at runtime actually has 253 nesting levels. So we end up +// calling String on something that is of type [][]*pwn instead of +// something of type *pwn. The way arg passing in Go works, the +// backing store pointer for the outer slice becomes the "this" +// pointer of the String method, which points to the inner []*pwn +// slice. The String method then modifies the length of that inner +// slice. +package main + +import "fmt" + +type pwn struct { + a [3]uint +} + +func (this *pwn) String() string { + this.a[1] = 7 // update length + return "" +} + +func main() { + var a pwn + s := [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]*pwn{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{&a}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} // depth 253 + fmt.Sprint(s) + n := len(s[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]) // depth 252, type []*pwn + if n != 1 { + panic(fmt.Sprintf("length was changed, want 1 got %d", n)) + } +} diff --git a/test/fixedbugs/issue29612.dir/main.go b/test/fixedbugs/issue29612.dir/main.go index 9dbc4c4c..97415c44 100644 --- a/test/fixedbugs/issue29612.dir/main.go +++ b/test/fixedbugs/issue29612.dir/main.go @@ -10,8 +10,10 @@ package main import ( - ssa1 "./p1/ssa" - ssa2 "./p2/ssa" + "fmt" + + ssa1 "issue29612.dir/p1/ssa" + ssa2 "issue29612.dir/p2/ssa" ) func main() { @@ -21,4 +23,27 @@ func main() { v2 := &ssa2.T{} ssa2.Works(v2) ssa2.Panics(v2) // This call must not panic + + swt(v1, 1) + swt(v2, 2) +} + +//go:noinline +func swt(i interface{}, want int) { + var got int + switch i.(type) { + case *ssa1.T: + got = 1 + case *ssa2.T: + got = 2 + + case int8, int16, int32, int64: + got = 3 + case uint8, uint16, uint32, uint64: + got = 4 + } + + if got != want { + panic(fmt.Sprintf("switch %v: got %d, want %d", i, got, want)) + } } diff --git a/test/fixedbugs/issue29870b.go b/test/fixedbugs/issue29870b.go index 1bac566b..2d5f6385 100644 --- a/test/fixedbugs/issue29870b.go +++ b/test/fixedbugs/issue29870b.go @@ -10,5 +10,5 @@ package main func _() { - x := 7 // ERROR "x declared and not used" + x := 7 // ERROR "x declared but not used" } diff --git a/test/fixedbugs/issue31053.dir/f1.go b/test/fixedbugs/issue31053.dir/f1.go new file mode 100644 index 00000000..610f3938 --- /dev/null +++ b/test/fixedbugs/issue31053.dir/f1.go @@ -0,0 +1,18 @@ +// 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. + +package f1 + +type Foo struct { + doneChan chan bool + Name string + fOO int + hook func() +} + +func (f *Foo) Exported() { +} + +func (f *Foo) unexported() { +} diff --git a/test/fixedbugs/issue31053.dir/main.go b/test/fixedbugs/issue31053.dir/main.go new file mode 100644 index 00000000..895c2621 --- /dev/null +++ b/test/fixedbugs/issue31053.dir/main.go @@ -0,0 +1,42 @@ +// errorcheck + +// 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. + +package p + +import "./f1" + +func main() { + f := f1.Foo{ + doneChan: nil, // ERROR "cannot refer to unexported field 'doneChan' in struct literal of type f1.Foo" + DoneChan: nil, // ERROR "unknown field 'DoneChan' in struct literal of type f1.Foo" + Name: "hey", + name: "there", // ERROR "unknown field 'name' in struct literal of type f1.Foo .but does have Name." + noSuchPrivate: true, // ERROR "unknown field 'noSuchPrivate' in struct literal of type f1.Foo" + NoSuchPublic: true, // ERROR "unknown field 'NoSuchPublic' in struct literal of type f1.Foo" + foo: true, // ERROR "unknown field 'foo' in struct literal of type f1.Foo" + hook: func() {}, // ERROR "cannot refer to unexported field 'hook' in struct literal of type f1.Foo" + unexported: func() {}, // ERROR "unknown field 'unexported' in struct literal of type f1.Foo" + Exported: func() {}, // ERROR "unknown field 'Exported' in struct literal of type f1.Foo" + } + f.doneChan = nil // ERROR "f.doneChan undefined .cannot refer to unexported field or method doneChan." + f.DoneChan = nil // ERROR "f.DoneChan undefined .type f1.Foo has no field or method DoneChan." + f.name = nil // ERROR "f.name undefined .type f1.Foo has no field or method name, but does have Name." + + _ = f.doneChan // ERROR "f.doneChan undefined .cannot refer to unexported field or method doneChan." + _ = f.DoneChan // ERROR "f.DoneChan undefined .type f1.Foo has no field or method DoneChan." + _ = f.Name + _ = f.name // ERROR "f.name undefined .type f1.Foo has no field or method name, but does have Name." + _ = f.noSuchPrivate // ERROR "f.noSuchPrivate undefined .type f1.Foo has no field or method noSuchPrivate." + _ = f.NoSuchPublic // ERROR "f.NoSuchPublic undefined .type f1.Foo has no field or method NoSuchPublic." + _ = f.foo // ERROR "f.foo undefined .type f1.Foo has no field or method foo." + _ = f.Exported + _ = f.exported // ERROR "f.exported undefined .type f1.Foo has no field or method exported, but does have Exported." + _ = f.Unexported // ERROR "f.Unexported undefined .type f1.Foo has no field or method Unexported." + _ = f.unexported // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported." + f.unexported = 10 // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported." + f.unexported() // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported." + _ = f.hook // ERROR "f.hook undefined .cannot refer to unexported field or method hook." +} diff --git a/test/fixedbugs/issue31053.go b/test/fixedbugs/issue31053.go new file mode 100644 index 00000000..a33d3ff3 --- /dev/null +++ b/test/fixedbugs/issue31053.go @@ -0,0 +1,7 @@ +// errorcheckdir + +// 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. + +package ignored diff --git a/test/fixedbugs/issue31573.go b/test/fixedbugs/issue31573.go index fb4fdc81..c9ea84bb 100644 --- a/test/fixedbugs/issue31573.go +++ b/test/fixedbugs/issue31573.go @@ -9,7 +9,7 @@ package p func f(...*int) {} // ERROR "can inline f$" func g() { - defer f() // ERROR "... argument does not escape$" + defer f() defer f(new(int)) // ERROR "... argument does not escape$" "new\(int\) does not escape$" defer f(new(int), new(int)) // ERROR "... argument does not escape$" "new\(int\) does not escape$" @@ -18,7 +18,7 @@ func g() { 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$" - go f() // ERROR "... argument 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$" @@ -28,7 +28,7 @@ func g() { go f([]*int{new(int), new(int)}...) // ERROR "\[\]\*int literal escapes to heap$" "new\(int\) escapes to heap$" for { - defer f() // ERROR "... argument escapes to heap$" + defer f() defer f(new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" defer f(new(int), new(int)) // ERROR "... argument escapes to heap$" "new\(int\) escapes to heap$" @@ -37,7 +37,7 @@ func g() { 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$" - go f() // ERROR "... argument 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$" diff --git a/test/fixedbugs/issue31747.go b/test/fixedbugs/issue31747.go index dfb585c6..420fe307 100644 --- a/test/fixedbugs/issue31747.go +++ b/test/fixedbugs/issue31747.go @@ -8,11 +8,11 @@ package p // numeric literals const ( - _ = 1_000 // ERROR "underscores in numeric literals only supported as of -lang=go1.13" - _ = 0b111 // ERROR "binary literals only supported as of -lang=go1.13" - _ = 0o567 // ERROR "0o/0O-style octal literals only supported as of -lang=go1.13" + _ = 1_000 // ERROR "underscores in numeric literals requires go1.13 or later \(-lang was set to go1.12; check go.mod\)" + _ = 0b111 // ERROR "binary literals requires go1.13 or later" + _ = 0o567 // ERROR "0o/0O-style octal literals requires go1.13 or later" _ = 0xabc // ok - _ = 0x0p1 // ERROR "hexadecimal floating-point literals only supported as of -lang=go1.13" + _ = 0x0p1 // ERROR "hexadecimal floating-point literals requires go1.13 or later" _ = 0B111 // ERROR "binary" _ = 0O567 // ERROR "octal" @@ -29,6 +29,6 @@ const ( // signed shift counts var ( s int - _ = 1 << s // ERROR "signed shift count type int, only supported as of -lang=go1.13" + _ = 1 << s // ERROR "invalid operation: 1 << s \(signed shift count type int\) requires go1.13 or later" _ = 1 >> s // ERROR "signed shift count" ) diff --git a/test/fixedbugs/issue32133.go b/test/fixedbugs/issue32133.go new file mode 100644 index 00000000..f3cca87a --- /dev/null +++ b/test/fixedbugs/issue32133.go @@ -0,0 +1,43 @@ +// errorcheck + +// 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. + +package p + +// errors for the //line-adjusted code below +// ERROR "newline in string" +// ERROR "newline in character literal|newline in rune literal" +// ERROR "newline in string" +// ERROR "string not terminated" + +//line :10:1 +import "foo + +//line :19:1 +func _() { + 0x // ERROR "hexadecimal literal has no digits" +} + +func _() { + 0x1.0 // ERROR "hexadecimal mantissa requires a 'p' exponent" +} + +func _() { + 0_i // ERROR "'_' must separate successive digits" +} + +func _() { +//line :11:1 + ' +} + +func _() { +//line :12:1 + " +} + +func _() { +//line :13:1 + `
\ No newline at end of file diff --git a/test/fixedbugs/issue32187.go b/test/fixedbugs/issue32187.go new file mode 100644 index 00000000..9c8c9c26 --- /dev/null +++ b/test/fixedbugs/issue32187.go @@ -0,0 +1,60 @@ +// run + +// 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. + +// short-circuiting interface-to-concrete comparisons +// will not miss panics + +package main + +import ( + "log" + "strings" +) + +func main() { + var ( + x interface{} + p *int + s []int + l *interface{} + r []*int + ) + tests := []struct { + name string + errStr string + f func() + }{ + {"switch case", "", func() { + switch x { + case x.(*int): + } + }}, + {"interface conversion", "", func() { _ = x == x.(error) }}, + {"type assertion", "", func() { _ = x == x.(*int) }}, + {"out of bounds", "", func() { _ = x == s[1] }}, + {"nil pointer dereference #1", "", func() { _ = x == *p }}, + {"nil pointer dereference #2", "nil pointer dereference", func() { _ = *l == r[0] }}, + } + + for _, tc := range tests { + testFuncShouldPanic(tc.name, tc.errStr, tc.f) + } +} + +func testFuncShouldPanic(name, errStr string, f func()) { + defer func() { + e := recover() + if e == nil { + log.Fatalf("%s: comparison did not panic\n", name) + } + if errStr != "" { + if !strings.Contains(e.(error).Error(), errStr) { + log.Fatalf("%s: wrong panic message\n", name) + } + } + }() + f() +} diff --git a/test/fixedbugs/issue32454.go b/test/fixedbugs/issue32454.go new file mode 100644 index 00000000..70895c97 --- /dev/null +++ b/test/fixedbugs/issue32454.go @@ -0,0 +1,23 @@ +// compile + +// 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. + +package p + +type T struct { + s string + f float64 +} + +func f() { + var f float64 + var st T + for { + switch &st.f { + case &f: + f = 1 + } + } +} diff --git a/test/fixedbugs/issue32723.go b/test/fixedbugs/issue32723.go new file mode 100644 index 00000000..7d9e403f --- /dev/null +++ b/test/fixedbugs/issue32723.go @@ -0,0 +1,22 @@ +// errorcheck + +// 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. + +// Complex literal comparison + +package p + +const x = 1i +const y = 1i < 2i // ERROR "invalid operation: .*not defined on untyped complex" +const z = x < 2i // ERROR "invalid operation: .*not defined on untyped complex" + +func f() { + _ = 1i < 2i // ERROR "invalid operation: .*not defined on untyped complex" + _ = 1i < 2 // ERROR "invalid operation: .*not defined on untyped complex" + _ = 1 < 2i // ERROR "invalid operation: .*not defined on untyped complex" + + c := 1i + _ = c < 2i // ERROR "invalid operation: .*not defined on complex128" +} diff --git a/test/fixedbugs/issue33020a.dir/a.go b/test/fixedbugs/issue33020a.dir/a.go new file mode 100644 index 00000000..91764982 --- /dev/null +++ b/test/fixedbugs/issue33020a.dir/a.go @@ -0,0 +1,13 @@ +// 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. + +package a + +type FArg func(args []string) error + +type Command struct { + Name string + Arg1 FArg + Arg2 func(args []string) error +} diff --git a/test/fixedbugs/issue33020a.dir/b.go b/test/fixedbugs/issue33020a.dir/b.go new file mode 100644 index 00000000..5b0f9d86 --- /dev/null +++ b/test/fixedbugs/issue33020a.dir/b.go @@ -0,0 +1,14 @@ +// 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. + +package main + +import "./a" + +var Cmd = &a.Command{ + Name: "test", +} + +func main() { +} diff --git a/test/fixedbugs/issue33020a.go b/test/fixedbugs/issue33020a.go new file mode 100644 index 00000000..cfe010e9 --- /dev/null +++ b/test/fixedbugs/issue33020a.go @@ -0,0 +1,9 @@ +// compiledir + +// 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. + +// Issue 33020: gollvm assert in Llvm_backend::materializeComposite + +package ignored diff --git a/test/fixedbugs/issue33275.go b/test/fixedbugs/issue33275.go new file mode 100644 index 00000000..f2ec24db --- /dev/null +++ b/test/fixedbugs/issue33275.go @@ -0,0 +1,34 @@ +// skip + +// 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. + +package main + +import ( + "fmt" + "time" +) + +func main() { + // Make a big map. + m := map[int]int{} + for i := 0; i < 100000; i++ { + m[i] = i + } + c := make(chan string) + go func() { + // Print the map. + s := fmt.Sprintln(m) + c <- s + }() + go func() { + time.Sleep(1 * time.Millisecond) + // Add an extra item to the map while iterating. + m[-1] = -1 + c <- "" + }() + <-c + <-c +} diff --git a/test/fixedbugs/issue33275_run.go b/test/fixedbugs/issue33275_run.go new file mode 100644 index 00000000..f3e2e14f --- /dev/null +++ b/test/fixedbugs/issue33275_run.go @@ -0,0 +1,25 @@ +// +build !nacl,!js +// run + +// 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. + +// Make sure we don't get an index out of bounds error +// while trying to print a map that is concurrently modified. +// The runtime might complain (throw) if it detects the modification, +// so we have to run the test as a subprocess. + +package main + +import ( + "os/exec" + "strings" +) + +func main() { + out, _ := exec.Command("go", "run", "fixedbugs/issue33275.go").CombinedOutput() + if strings.Contains(string(out), "index out of range") { + panic(`go run issue33275.go reported "index out of range"`) + } +} diff --git a/test/fixedbugs/issue33386.go b/test/fixedbugs/issue33386.go new file mode 100644 index 00000000..afc27e62 --- /dev/null +++ b/test/fixedbugs/issue33386.go @@ -0,0 +1,29 @@ +// errorcheck + +// 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. + +// Verify that we don't get spurious follow-on errors +// after a missing expression. Specifically, the parser +// shouldn't skip over closing parentheses of any kind. + +package p + +func _() { + go func() { // no error here about goroutine + send <- + }() // ERROR "expecting expression" +} + +func _() { + defer func() { // no error here about deferred function + 1 + + }() // ERROR "expecting expression" +} + +func _() { + _ = (1 +) // ERROR "expecting expression" + _ = a[2 +] // ERROR "expecting expression" + _ = []int{1, 2, 3 + } // ERROR "expecting expression" +} diff --git a/test/fixedbugs/issue33460.go b/test/fixedbugs/issue33460.go new file mode 100644 index 00000000..1061d3e7 --- /dev/null +++ b/test/fixedbugs/issue33460.go @@ -0,0 +1,37 @@ +// errorcheck + +// 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. + +package p + +const ( + zero = iota + one + two + three +) + +const iii int = 0x3 + +func f(v int) { + switch v { + case zero, one: + case two, one: // ERROR "previous case at LINE-1" + + case three: + case 3: // ERROR "previous case at LINE-1" + case iii: // ERROR "previous case at LINE-2" + } +} + +const b = "b" + +var _ = map[string]int{ + "a": 0, + b: 1, + "a": 2, // ERROR "previous key at LINE-2" + "b": 3, // ERROR "previous key at LINE-2" + "b": 4, // ERROR "previous key at LINE-3" +} diff --git a/test/fixedbugs/issue33724.go b/test/fixedbugs/issue33724.go new file mode 100644 index 00000000..a4ecddc0 --- /dev/null +++ b/test/fixedbugs/issue33724.go @@ -0,0 +1,45 @@ +// run +package main + +import ( + "fmt" + "runtime/debug" + "strings" +) + +type Inner struct { + Err int +} + +func (i *Inner) NotExpectedInStackTrace() int { + if i == nil { + return 86 + } + return 17 + i.Err +} + +type Outer struct { + Inner +} + +func ExpectedInStackTrace() { + var o *Outer + println(o.NotExpectedInStackTrace()) +} + +func main() { + defer func() { + if r := recover(); r != nil { + stacktrace := string(debug.Stack()) + if strings.Contains(stacktrace, "NotExpectedInStackTrace") { + fmt.Println("FAIL, stacktrace contains NotExpectedInStackTrace") + } + if !strings.Contains(stacktrace, "ExpectedInStackTrace") { + fmt.Println("FAIL, stacktrace does not contain ExpectedInStackTrace") + } + } else { + fmt.Println("FAIL, should have panicked but did not") + } + }() + ExpectedInStackTrace() +} diff --git a/test/fixedbugs/issue33739.dir/a.go b/test/fixedbugs/issue33739.dir/a.go new file mode 100644 index 00000000..7eb5b927 --- /dev/null +++ b/test/fixedbugs/issue33739.dir/a.go @@ -0,0 +1,11 @@ +// 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. + +package a + +func F() func() { + return f +} + +func f() {} diff --git a/test/fixedbugs/issue33739.dir/b.go b/test/fixedbugs/issue33739.dir/b.go new file mode 100644 index 00000000..caca1ec6 --- /dev/null +++ b/test/fixedbugs/issue33739.dir/b.go @@ -0,0 +1,11 @@ +// 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. + +package main + +import "a" + +func main() { + a.F()() +} diff --git a/test/fixedbugs/issue33739.go b/test/fixedbugs/issue33739.go new file mode 100644 index 00000000..b7707822 --- /dev/null +++ b/test/fixedbugs/issue33739.go @@ -0,0 +1,9 @@ +// rundir + +// 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. + +// Issue 33739: gccgo undefined symbol with cross-package inlining + +package ignored diff --git a/test/fixedbugs/issue33866.dir/a.go b/test/fixedbugs/issue33866.dir/a.go new file mode 100644 index 00000000..9c782c5e --- /dev/null +++ b/test/fixedbugs/issue33866.dir/a.go @@ -0,0 +1,18 @@ +// 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. + +package a + +type Builder struct { + x int +} + +func (tb Builder) Build() (out struct { + x interface{} + s string +}) { + out.x = nil + out.s = "hello!" + return +} diff --git a/test/fixedbugs/issue33866.dir/b.go b/test/fixedbugs/issue33866.dir/b.go new file mode 100644 index 00000000..aa2a3227 --- /dev/null +++ b/test/fixedbugs/issue33866.dir/b.go @@ -0,0 +1,15 @@ +// 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. + +package b + +import "./a" + +type ( + ABuilder = a.Builder +) + +func Bfunc() ABuilder { + return ABuilder{} +} diff --git a/test/fixedbugs/issue33866.go b/test/fixedbugs/issue33866.go new file mode 100644 index 00000000..220c732a --- /dev/null +++ b/test/fixedbugs/issue33866.go @@ -0,0 +1,9 @@ +// compiledir + +// 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. + +// Issue 33866: assert in gccgo during compilation + +package ignored diff --git a/test/fixedbugs/issue33903.go b/test/fixedbugs/issue33903.go new file mode 100644 index 00000000..de032822 --- /dev/null +++ b/test/fixedbugs/issue33903.go @@ -0,0 +1,16 @@ +// compile + +// 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. + +// Check that the shortcircuit pass correctly handles infinite loops. + +package p + +func f() { + var p, q bool + for { + p = p && q + } +} diff --git a/test/fixedbugs/issue34123.go b/test/fixedbugs/issue34123.go new file mode 100644 index 00000000..f50cd02a --- /dev/null +++ b/test/fixedbugs/issue34123.go @@ -0,0 +1,43 @@ +// run + +// 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. + +// Make sure that the line number is reported correctly +// for faulting instructions. + +package main + +import ( + "fmt" + "runtime" +) + +var x byte +var p *byte + +//go:noinline +func f() { + q := p + x = 11 // line 23 + *q = 12 // line 24 +} +func main() { + defer func() { + recover() + var pcs [10]uintptr + n := runtime.Callers(1, pcs[:]) + frames := runtime.CallersFrames(pcs[:n]) + for { + f, more := frames.Next() + if f.Function == "main.f" && f.Line != 24 { + panic(fmt.Errorf("expected line 24, got line %d", f.Line)) + } + if !more { + break + } + } + }() + f() +} diff --git a/test/fixedbugs/issue34329.go b/test/fixedbugs/issue34329.go new file mode 100644 index 00000000..790686e3 --- /dev/null +++ b/test/fixedbugs/issue34329.go @@ -0,0 +1,14 @@ +// errorcheck -lang=go1.13 + +// 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. + +package p + +type I interface { M() } + +type _ interface { + I + I // ERROR "duplicate method M" +} diff --git a/test/fixedbugs/issue34395.go b/test/fixedbugs/issue34395.go new file mode 100644 index 00000000..eb5a8558 --- /dev/null +++ b/test/fixedbugs/issue34395.go @@ -0,0 +1,17 @@ +// run + +// 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. + +// Test that a binary with a large data section can load. This failed on wasm. + +package main + +var test = [100 * 1024 * 1024]byte{42} + +func main() { + if test[0] != 42 { + panic("bad") + } +} diff --git a/test/fixedbugs/issue34503.dir/a.go b/test/fixedbugs/issue34503.dir/a.go new file mode 100644 index 00000000..2c149135 --- /dev/null +++ b/test/fixedbugs/issue34503.dir/a.go @@ -0,0 +1,15 @@ +// 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. + +package a + +import "unsafe" + +type HookFunc func(x uint64) + +var HookV unsafe.Pointer + +func Hook(x uint64) { + (*(*HookFunc)(HookV))(x) +} diff --git a/test/fixedbugs/issue34503.dir/b.go b/test/fixedbugs/issue34503.dir/b.go new file mode 100644 index 00000000..21bdfcc1 --- /dev/null +++ b/test/fixedbugs/issue34503.dir/b.go @@ -0,0 +1,11 @@ +// 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. + +package b + +import "a" + +func Bfunc() { + a.Hook(101) +} diff --git a/test/fixedbugs/issue34503.go b/test/fixedbugs/issue34503.go new file mode 100644 index 00000000..d843df70 --- /dev/null +++ b/test/fixedbugs/issue34503.go @@ -0,0 +1,9 @@ +// compiledir + +// 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. + +// Issue 34503: gccgo compiler error importing inlinable function + +package ignored diff --git a/test/fixedbugs/issue34520.go b/test/fixedbugs/issue34520.go new file mode 100644 index 00000000..d92d4ccb --- /dev/null +++ b/test/fixedbugs/issue34520.go @@ -0,0 +1,12 @@ +// compile + +// 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. + +package p + +func f() { + for true { + } +} diff --git a/test/fixedbugs/issue34577.dir/a.go b/test/fixedbugs/issue34577.dir/a.go new file mode 100644 index 00000000..b6af5556 --- /dev/null +++ b/test/fixedbugs/issue34577.dir/a.go @@ -0,0 +1,27 @@ +// 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. + +package a + +type A struct { + x int +} + +type AI interface { + bar() +} + +type AC int + +func (ab AC) bar() { +} + +const ( + ACC = AC(101) +) + +//go:noinline +func W(a A, k, v interface{}) A { + return A{3} +} diff --git a/test/fixedbugs/issue34577.dir/b.go b/test/fixedbugs/issue34577.dir/b.go new file mode 100644 index 00000000..bbcd1af5 --- /dev/null +++ b/test/fixedbugs/issue34577.dir/b.go @@ -0,0 +1,23 @@ +// 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. + +package b + +import "a" + +type B struct { + s string +} + +func (b B) Func(x a.A) a.A { + return a.W(x, k, b) +} + +type ktype int + +const k ktype = 0 + +func Func2() a.AI { + return a.ACC +} diff --git a/test/fixedbugs/issue34577.go b/test/fixedbugs/issue34577.go new file mode 100644 index 00000000..b4caaebb --- /dev/null +++ b/test/fixedbugs/issue34577.go @@ -0,0 +1,9 @@ +// compiledir + +// 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. + +// Issue 34577: gccgo compiler error emitting export data + +package ignored diff --git a/test/fixedbugs/issue34723.go b/test/fixedbugs/issue34723.go new file mode 100644 index 00000000..402d465a --- /dev/null +++ b/test/fixedbugs/issue34723.go @@ -0,0 +1,70 @@ +// errorcheck -0 -d=wb + +// 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. + +// Make sure we don't introduce write barriers where we +// don't need them. These cases are writing pointers to +// globals to zeroed memory. + +package main + +func f1() []string { + return []string{"a"} +} + +func f2() []string { + return []string{"a", "b"} +} + +type T struct { + a [6]*int +} + +func f3() *T { + t := new(T) + t.a[0] = &g + t.a[1] = &g + t.a[2] = &g + t.a[3] = &g + t.a[4] = &g + t.a[5] = &g + return t +} + +func f4() *T { + t := new(T) + t.a[5] = &g + t.a[4] = &g + t.a[3] = &g + t.a[2] = &g + t.a[1] = &g + t.a[0] = &g + return t +} + +func f5() *T { + t := new(T) + t.a[4] = &g + t.a[2] = &g + t.a[0] = &g + t.a[3] = &g + t.a[1] = &g + t.a[5] = &g + return t +} + +type U struct { + a [65]*int +} + +func f6() *U { + u := new(U) + u.a[63] = &g + // This offset is too large: we only track the first 64 pointers for zeroness. + u.a[64] = &g // ERROR "write barrier" + return u +} + +var g int diff --git a/test/fixedbugs/issue34966.go b/test/fixedbugs/issue34966.go new file mode 100644 index 00000000..f920e71a --- /dev/null +++ b/test/fixedbugs/issue34966.go @@ -0,0 +1,14 @@ +// compile -d=checkptr + +// 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. + +package p + +import "unsafe" + +type ptr unsafe.Pointer + +func f(p ptr) *int { return (*int)(p) } +func g(p ptr) ptr { return ptr(uintptr(p) + 1) } diff --git a/test/fixedbugs/issue34968.go b/test/fixedbugs/issue34968.go new file mode 100644 index 00000000..6b1dbd16 --- /dev/null +++ b/test/fixedbugs/issue34968.go @@ -0,0 +1,15 @@ +// +build cgo +// run -gcflags=all=-d=checkptr + +// 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. + +package main + +// #include <stdlib.h> +import "C" + +func main() { + C.malloc(100) +} diff --git a/test/fixedbugs/issue35027.go b/test/fixedbugs/issue35027.go new file mode 100644 index 00000000..d4b0be52 --- /dev/null +++ b/test/fixedbugs/issue35027.go @@ -0,0 +1,23 @@ +// run -gcflags=-d=checkptr + +// 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. + +package main + +import ( + "reflect" + "unsafe" +) + +var s []int + +func main() { + s = []int{42} + h := (*reflect.SliceHeader)(unsafe.Pointer(&s)) + x := *(*int)(unsafe.Pointer(h.Data)) + if x != 42 { + panic(x) + } +} diff --git a/test/fixedbugs/issue35073.go b/test/fixedbugs/issue35073.go new file mode 100644 index 00000000..dc8ce3a9 --- /dev/null +++ b/test/fixedbugs/issue35073.go @@ -0,0 +1,23 @@ +// run -gcflags=-d=checkptr + +// 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. + +// Test that reflect.Value.UnsafeAddr/Pointer is handled +// correctly by -d=checkptr + +package main + +import ( + "reflect" + "unsafe" +) + +func main() { + n := 10 + m := make(map[string]string) + + _ = unsafe.Pointer(reflect.ValueOf(&n).Elem().UnsafeAddr()) + _ = unsafe.Pointer(reflect.ValueOf(&m).Elem().Pointer()) +} diff --git a/test/fixedbugs/issue35157.go b/test/fixedbugs/issue35157.go new file mode 100644 index 00000000..c9c4899e --- /dev/null +++ b/test/fixedbugs/issue35157.go @@ -0,0 +1,20 @@ +// compile + +// 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. + +package p + +func f() { + var i int + var b *bool + var s0, s1, s2 string + + if *b { + s2 = s2[:1] + i = 1 + } + s1 = s1[i:-i+i] + s1[-i+i:i+2] + s1 = s0[i:-i] +} diff --git a/test/fixedbugs/issue35291.go b/test/fixedbugs/issue35291.go new file mode 100644 index 00000000..3cbdbf96 --- /dev/null +++ b/test/fixedbugs/issue35291.go @@ -0,0 +1,14 @@ +// errorcheck + +// 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. + +// Check error message for duplicated index in slice literal + +package p + +var s = []string{ + 1: "dup", + 1: "dup", // ERROR "duplicate index in slice literal: 1" +} diff --git a/test/fixedbugs/issue35518.go b/test/fixedbugs/issue35518.go new file mode 100644 index 00000000..52a0ae7e --- /dev/null +++ b/test/fixedbugs/issue35518.go @@ -0,0 +1,44 @@ +// errorcheck -0 -l -m=2 + +// 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. + +// This test makes sure that -m=2's escape analysis diagnostics don't +// go into an infinite loop when handling negative dereference +// cycles. The critical thing being tested here is that compilation +// succeeds ("errorcheck -0"), not any particular diagnostic output, +// hence the very lax ERROR patterns below. + +package p + +type Node struct { + Orig *Node +} + +var sink *Node + +func f1() { + var n Node // ERROR "." + n.Orig = &n + + m := n // ERROR "." + sink = &m +} + +func f2() { + var n1, n2 Node // ERROR "." + n1.Orig = &n2 + n2 = n1 + + m := n2 // ERROR "." + sink = &m +} + +func f3() { + var n1, n2 Node // ERROR "." + n1.Orig = &n1 + n1.Orig = &n2 + + sink = n1.Orig.Orig +} diff --git a/test/fixedbugs/issue35576.go b/test/fixedbugs/issue35576.go new file mode 100644 index 00000000..8228555c --- /dev/null +++ b/test/fixedbugs/issue35576.go @@ -0,0 +1,16 @@ +// run + +// 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. + +// Check print/println(f()) is allowed where f() is multi-value. + +package main + +func f() (int16, float64, string) { return -42, 42.0, "x" } + +func main() { + print(f()) + println(f()) +} diff --git a/test/fixedbugs/issue35576.out b/test/fixedbugs/issue35576.out new file mode 100644 index 00000000..2aefe3ed --- /dev/null +++ b/test/fixedbugs/issue35576.out @@ -0,0 +1 @@ +-42+4.200000e+001x-42 +4.200000e+001 x diff --git a/test/fixedbugs/issue35586.dir/a.go b/test/fixedbugs/issue35586.dir/a.go new file mode 100644 index 00000000..f509b254 --- /dev/null +++ b/test/fixedbugs/issue35586.dir/a.go @@ -0,0 +1,9 @@ +// 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. + +package a + +func D(_ string, _ int) (uint64, string) { + return 101, "bad" +} diff --git a/test/fixedbugs/issue35586.dir/b.go b/test/fixedbugs/issue35586.dir/b.go new file mode 100644 index 00000000..e8b674fe --- /dev/null +++ b/test/fixedbugs/issue35586.dir/b.go @@ -0,0 +1,11 @@ +// 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. + +package b + +import "a" + +func F(addr string) (uint64, string) { + return a.D(addr, 32) +} diff --git a/test/fixedbugs/issue35586.go b/test/fixedbugs/issue35586.go new file mode 100644 index 00000000..0d522b17 --- /dev/null +++ b/test/fixedbugs/issue35586.go @@ -0,0 +1,11 @@ +// compiledir + +// 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. + +// Issue 35586: gollvm compiler crash building docker-ce; the problem +// involves inlining a function that has multiple no-name ("_") parameters. +// + +package ignored diff --git a/test/fixedbugs/issue35652.go b/test/fixedbugs/issue35652.go new file mode 100644 index 00000000..178a84d0 --- /dev/null +++ b/test/fixedbugs/issue35652.go @@ -0,0 +1,28 @@ +// compile + +// 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. + +package p + +func e() { + for true { + if true { + continue + } + } +} + +func g() {} + +func f() { + i := 0 + if true { + i++ + } + for true { + continue + g() + } +} diff --git a/test/fixedbugs/issue36085.dir/a.go b/test/fixedbugs/issue36085.dir/a.go new file mode 100644 index 00000000..07cabcd2 --- /dev/null +++ b/test/fixedbugs/issue36085.dir/a.go @@ -0,0 +1,3 @@ +package a + +type W = map[int32]interface{} diff --git a/test/fixedbugs/issue36085.dir/b.go b/test/fixedbugs/issue36085.dir/b.go new file mode 100644 index 00000000..c5ee2697 --- /dev/null +++ b/test/fixedbugs/issue36085.dir/b.go @@ -0,0 +1,8 @@ +package main + +import "a" + +var w a.W +var X interface{} = &w + +func main() {} diff --git a/test/fixedbugs/issue36085.go b/test/fixedbugs/issue36085.go new file mode 100644 index 00000000..69d4490f --- /dev/null +++ b/test/fixedbugs/issue36085.go @@ -0,0 +1,11 @@ +// compiledir + +// 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. + +// Issue 36085: gccgo compiler did not generate type descriptor +// for pointer to type alias defined in another package, causing +// linking error. + +package ignored diff --git a/test/fixedbugs/issue36259.go b/test/fixedbugs/issue36259.go new file mode 100644 index 00000000..246eb352 --- /dev/null +++ b/test/fixedbugs/issue36259.go @@ -0,0 +1,28 @@ +// compile + +// 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. + +package main + +func rotate(s []int, m int) { + l := len(s) + m = m % l + buf := make([]int, m) + + copy(buf, s) + copy(s, s[m:]) + copy(s[l-m:], buf) +} + +func main() { + a0 := [...]int{1,2,3,4,5} + println(a0[0]) + + rotate(a0[:], 1) + println(a0[0]) + + rotate(a0[:], -3) + println(a0[0]) +} diff --git a/test/fixedbugs/issue36437.go b/test/fixedbugs/issue36437.go new file mode 100644 index 00000000..f96544be --- /dev/null +++ b/test/fixedbugs/issue36437.go @@ -0,0 +1,49 @@ +// run + +// +build !nacl,!js + +// 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. + +// Tests that when non-existent files are passed to the +// compiler, such as in: +// go tool compile foo +// we don't print the beginning position: +// foo:0: open foo: no such file or directory +// but instead omit it and print out: +// open foo: no such file or directory + +package main + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "regexp" +) + +func main() { + tmpDir, err := ioutil.TempDir("", "issue36437") + if err != nil { + panic(err) + } + defer os.RemoveAll(tmpDir) + + msgOrErr := func(msg []byte, err error) string { + if len(msg) == 0 && err != nil { + return err.Error() + } + return string(msg) + } + + filename := "non-existent.go" + output, err := exec.Command("go", "tool", "compile", filename).CombinedOutput() + got := msgOrErr(output, err) + + regFilenamePos := regexp.MustCompile(filename + ":\\d+") + if regFilenamePos.MatchString(got) { + fmt.Printf("Error message must not contain filename:pos, but got:\n%q\n", got) + } +} diff --git a/test/fixedbugs/issue36516.go b/test/fixedbugs/issue36516.go new file mode 100644 index 00000000..d4e28b63 --- /dev/null +++ b/test/fixedbugs/issue36516.go @@ -0,0 +1,27 @@ +// +build cgo,linux,amd64 +// run -race + +// 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" + "testing" + "unsafe" +) + +var buf [2]byte +var x unsafe.Pointer = unsafe.Pointer(&buf[0]) + +func main() { + n := testing.AllocsPerRun(1000, func() { + x = unsafe.Pointer(uintptr(x) + 1) + x = unsafe.Pointer(uintptr(x) - 1) + }) + if n > 0 { + panic(fmt.Sprintf("too many allocations; want 0 got %f", n)) + } +} diff --git a/test/fixedbugs/issue36705.go b/test/fixedbugs/issue36705.go new file mode 100644 index 00000000..83e41368 --- /dev/null +++ b/test/fixedbugs/issue36705.go @@ -0,0 +1,27 @@ +// +build cgo +// 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 + +// #include <stdlib.h> +// #include <unistd.h> +import "C" + +import "os" + +func main() { + os.Setenv("FOO", "bar") + s := C.GoString(C.getenv(C.CString("FOO"))) + if s != "bar" { + panic("bad setenv, environment variable only has value \"" + s + "\"") + } + os.Unsetenv("FOO") + s = C.GoString(C.getenv(C.CString("FOO"))) + if s != "" { + panic("bad unsetenv, environment variable still has value \"" + s + "\"") + } +} diff --git a/test/fixedbugs/issue36723.go b/test/fixedbugs/issue36723.go new file mode 100644 index 00000000..e748d9a7 --- /dev/null +++ b/test/fixedbugs/issue36723.go @@ -0,0 +1,26 @@ +// 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. + +// Issue 36723: fail to compile on PPC64 when SSA check is on. + +package p + +import "unsafe" + +type T struct { + a, b, c, d uint8 + x [10]int32 +} + +func F(p *T, i uintptr) int32 { + // load p.x[i] using unsafe, derived from runtime.pcdatastart + _ = *p + return *(*int32)(add(unsafe.Pointer(&p.d), unsafe.Sizeof(p.d)+i*unsafe.Sizeof(p.x[0]))) +} + +func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { + return unsafe.Pointer(uintptr(p) + x) +} diff --git a/test/fixedbugs/issue37246.go b/test/fixedbugs/issue37246.go new file mode 100644 index 00000000..fe476daa --- /dev/null +++ b/test/fixedbugs/issue37246.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. + +package main + +func main() { + var n, a, b int64 + for i := int64(2); i < 10; i++ { + for j := i; j < 10; j++ { + if ((n % (i * j)) == 0) && (j > 1 && (n/(i*j)) == 1) { + a, b = i, 0 + a = n / (i * j) + } + } + } + + if a != b && a != n { + println("yes") + } +} diff --git a/test/fixedbugs/issue37513.dir/main.go b/test/fixedbugs/issue37513.dir/main.go new file mode 100644 index 00000000..75106521 --- /dev/null +++ b/test/fixedbugs/issue37513.dir/main.go @@ -0,0 +1,27 @@ +// 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 ( + "bytes" + "fmt" + "os" + "os/exec" +) + +func main() { + if len(os.Args) > 1 { + // Generate a SIGILL. + sigill() + return + } + // Run ourselves with an extra argument. That process should SIGILL. + out, _ := exec.Command(os.Args[0], "foo").CombinedOutput() + want := "instruction bytes: 0xf 0xb 0xc3" + if !bytes.Contains(out, []byte(want)) { + fmt.Printf("got:\n%s\nwant:\n%s\n", string(out), want) + } +} +func sigill() diff --git a/test/fixedbugs/issue37513.dir/sigill_amd64.s b/test/fixedbugs/issue37513.dir/sigill_amd64.s new file mode 100644 index 00000000..43260c21 --- /dev/null +++ b/test/fixedbugs/issue37513.dir/sigill_amd64.s @@ -0,0 +1,7 @@ +// 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. + +TEXT ·sigill(SB),0,$0-0 + UD2 // generates a SIGILL + RET diff --git a/test/fixedbugs/issue37513.go b/test/fixedbugs/issue37513.go new file mode 100644 index 00000000..e05b2d86 --- /dev/null +++ b/test/fixedbugs/issue37513.go @@ -0,0 +1,9 @@ +// buildrundir + +// 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. + +// +build linux,amd64 darwin,amd64 linux,386 + +package ignored diff --git a/test/fixedbugs/issue37716.go b/test/fixedbugs/issue37716.go new file mode 100644 index 00000000..42d66dff --- /dev/null +++ b/test/fixedbugs/issue37716.go @@ -0,0 +1,32 @@ +// 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" + +// complicated enough to require a compile-generated hash function +type K struct { + a, b int32 // these get merged by the compiler into a single field, something typehash doesn't do + c float64 +} + +func main() { + k := K{a: 1, b: 2, c: 3} + + // Make a reflect map. + m := reflect.MakeMap(reflect.MapOf(reflect.TypeOf(K{}), reflect.TypeOf(true))) + m.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(true)) + + // The binary must not contain the type map[K]bool anywhere, or reflect.MapOf + // will use that type instead of making a new one. So use an equivalent named type. + type M map[K]bool + var x M + reflect.ValueOf(&x).Elem().Set(m) + if !x[k] { + panic("key not found") + } +} diff --git a/test/fixedbugs/issue37753.go b/test/fixedbugs/issue37753.go new file mode 100644 index 00000000..ac311e37 --- /dev/null +++ b/test/fixedbugs/issue37753.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 + +//go:noinline +func f(a, b uint) int { + return int(a-b) / 8 +} + +func main() { + if x := f(1, 2); x != 0 { + panic(x) + } +} diff --git a/test/fixedbugs/issue37975.go b/test/fixedbugs/issue37975.go new file mode 100644 index 00000000..a4e8f1f1 --- /dev/null +++ b/test/fixedbugs/issue37975.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. + +// Make sure runtime.panicmakeslice* are called. + +package main + +import "strings" + +func main() { + // Test typechecking passes if len is valid + // but cap is out of range for len's type. + var x byte + _ = make([]int, x, 300) + + capOutOfRange := func() { + i := 2 + s := make([]int, i, 1) + s[0] = 1 + } + lenOutOfRange := func() { + i := -1 + s := make([]int, i, 3) + s[0] = 1 + } + + tests := []struct { + f func() + panicStr string + }{ + {capOutOfRange, "cap out of range"}, + {lenOutOfRange, "len out of range"}, + } + + for _, tc := range tests { + shouldPanic(tc.panicStr, tc.f) + } + +} + +func shouldPanic(str string, f func()) { + defer func() { + err := recover() + runtimeErr := err.(error).Error() + if !strings.Contains(runtimeErr, str) { + panic("got panic " + runtimeErr + ", want " + str) + } + }() + + f() +} diff --git a/test/fixedbugs/issue38093.go b/test/fixedbugs/issue38093.go new file mode 100644 index 00000000..db92664a --- /dev/null +++ b/test/fixedbugs/issue38093.go @@ -0,0 +1,49 @@ +// +build js +// 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. + +// Test race condition between timers and wasm calls that led to memory corruption. + +package main + +import ( + "os" + "syscall/js" + "time" +) + +func main() { + ch1 := make(chan struct{}) + + go func() { + for { + time.Sleep(5 * time.Millisecond) + ch1 <- struct{}{} + } + }() + go func() { + for { + time.Sleep(8 * time.Millisecond) + ch1 <- struct{}{} + } + }() + go func() { + time.Sleep(2 * time.Second) + os.Exit(0) + }() + + for range ch1 { + ch2 := make(chan struct{}, 1) + f := js.FuncOf(func(this js.Value, args []js.Value) interface{} { + ch2 <- struct{}{} + return nil + }) + defer f.Release() + fn := js.Global().Get("Function").New("cb", "cb();") + fn.Invoke(f) + <-ch2 + } +} diff --git a/test/fixedbugs/issue38117.go b/test/fixedbugs/issue38117.go new file mode 100644 index 00000000..11edef7f --- /dev/null +++ b/test/fixedbugs/issue38117.go @@ -0,0 +1,17 @@ +// 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. + +// cmd/compile erroneously rejected conversions of constant values +// between int/float and complex types. + +package p + +const ( + _ = int(complex64(int(0))) + _ = float64(complex128(float64(0))) + + _ = int8(complex128(1000)) // ERROR "overflow" +) diff --git a/test/fixedbugs/issue38356.go b/test/fixedbugs/issue38356.go new file mode 100644 index 00000000..a1c7f467 --- /dev/null +++ b/test/fixedbugs/issue38356.go @@ -0,0 +1,54 @@ +// 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. + +// Make sure floating point operations that generate flags +// are scheduled correctly on s390x. + +package p + +func f1(x, y float64, z int) float64 { + a := x + y // generate flags + if z == 0 { // create basic block that does not clobber flags + return a + } + if a > 0 { // use flags in different basic block + return y + } + return x +} + +func f2(x, y float64, z int) float64 { + a := x - y // generate flags + if z == 0 { // create basic block that does not clobber flags + return a + } + if a > 0 { // use flags in different basic block + return y + } + return x +} + +func f3(x, y float32, z int) float32 { + a := x + y // generate flags + if z == 0 { // create basic block that does not clobber flags + return a + } + if a > 0 { // use flags in different basic block + return y + } + return x +} + +func f4(x, y float32, z int) float32 { + a := x - y // generate flags + if z == 0 { // create basic block that does not clobber flags + return a + } + if a > 0 { // use flags in different basic block + return y + } + return x +} diff --git a/test/fixedbugs/issue38359.go b/test/fixedbugs/issue38359.go new file mode 100644 index 00000000..a7550c7b --- /dev/null +++ b/test/fixedbugs/issue38359.go @@ -0,0 +1,19 @@ +// 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. + +// Make sure NaN-NaN compiles correctly. + +package p + +func f() { + var st struct { + f float64 + _, _ string + } + + f := 1e308 + st.f = 2*f - 2*f +} diff --git a/test/fixedbugs/issue38496.go b/test/fixedbugs/issue38496.go new file mode 100644 index 00000000..717aa5d4 --- /dev/null +++ b/test/fixedbugs/issue38496.go @@ -0,0 +1,20 @@ +// 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. + +// Make sure bounds check elision isn't confused with nil check elision. + +package main + +func main() { + defer func() { + err := recover() + if err == nil { + panic("failed to check nil ptr") + } + }() + var m [2]*int + _ = *m[1] // need a nil check, but not a bounds check +} diff --git a/test/fixedbugs/issue38690.go b/test/fixedbugs/issue38690.go new file mode 100644 index 00000000..af8688d1 --- /dev/null +++ b/test/fixedbugs/issue38690.go @@ -0,0 +1,65 @@ +// 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. + +// Make sure that literal value can be passed to struct +// blank field of array/struct type, see issue #38690. + +package main + +type A1 = [0]int +type A2 = [1]int + +type S1 struct{} + +type S2 struct { + x int +} + +type S3 = struct{} + +type S4 = struct{ x int } + +type S struct { + x int + _ [0]int + _ [1]int + _ A1 + _ A2 + _ S1 + _ S2 + _ S3 + _ S4 + _ [1]S4 +} + +var s = S{1, [0]int{}, [1]int{1}, A1{}, A2{1}, S1{}, S2{1}, S3{}, S4{1}, [1]S4{}} + +func main() { + f1() + mustPanic(f2) + mustPanic(f3) +} + +func f1() { + _ = S{1, [0]int{}, [1]int{1}, A1{}, A2{1}, S1{}, S2{1}, S3{}, S4{1}, [1]S4{}} +} + +func f2() { + _ = S{1, [0]int{}, [1]int{1}, A1{}, A2{1}, S1{}, S2{1}, S3{}, func() S4 { panic("") }(), [1]S4{}} +} + +func f3() { + _ = S{1, [0]int{}, [1]int{1}, A1{}, A2{1}, S1{}, S2{1}, S3{}, S4{1}, func() [1]S4 { panic("") }()} +} + +func mustPanic(f func()) { + defer func() { + if recover() == nil { + panic("expected panic, got nil") + } + }() + f() +} diff --git a/test/fixedbugs/issue38746.go b/test/fixedbugs/issue38746.go new file mode 100644 index 00000000..c670349e --- /dev/null +++ b/test/fixedbugs/issue38746.go @@ -0,0 +1,17 @@ +// 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 main + +var g *uint64 + +func main() { + var v uint64 + g = &v + v &^= (1 << 31) + v |= 1 << 63 + v &^= (1 << 63) +} diff --git a/test/fixedbugs/issue38916.go b/test/fixedbugs/issue38916.go new file mode 100644 index 00000000..fb2ee345 --- /dev/null +++ b/test/fixedbugs/issue38916.go @@ -0,0 +1,14 @@ +// 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(b bool, c complex128) func(complex128) complex128 { + return func(p complex128) complex128 { + b = (p+1i == 0) && b + return (p + 2i) * (p + 3i - c) + } +} diff --git a/test/fixedbugs/issue39472.go b/test/fixedbugs/issue39472.go new file mode 100644 index 00000000..61444a28 --- /dev/null +++ b/test/fixedbugs/issue39472.go @@ -0,0 +1,12 @@ +// compile -N + +// 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(x float64) bool { + x += 1 + return (x != 0) == (x != 0) +} diff --git a/test/fixedbugs/issue4085b.go b/test/fixedbugs/issue4085b.go index 6304ce07..cf27512d 100644 --- a/test/fixedbugs/issue4085b.go +++ b/test/fixedbugs/issue4085b.go @@ -19,29 +19,36 @@ func main() { shouldPanic("cap out of range", func() { _ = make(T, 0, n) }) shouldPanic("len out of range", func() { _ = make(T, int64(n)) }) shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) }) + testMakeInAppend(n) + var t *byte if unsafe.Sizeof(t) == 8 { // Test mem > maxAlloc var n2 int64 = 1 << 59 shouldPanic("len out of range", func() { _ = make(T, int(n2)) }) shouldPanic("cap out of range", func() { _ = make(T, 0, int(n2)) }) + testMakeInAppend(int(n2)) // Test elem.size*cap overflow n2 = 1<<63 - 1 shouldPanic("len out of range", func() { _ = make(T, int(n2)) }) shouldPanic("cap out of range", func() { _ = make(T, 0, int(n2)) }) + testMakeInAppend(int(n2)) + var x uint64 = 1<<64 - 1 + shouldPanic("len out of range", func() { _ = make([]byte, x) }) + shouldPanic("cap out of range", func() { _ = make(T, 0, x) }) + testMakeInAppend(int(x)) } else { n = 1<<31 - 1 shouldPanic("len out of range", func() { _ = make(T, n) }) shouldPanic("cap out of range", func() { _ = make(T, 0, n) }) shouldPanic("len out of range", func() { _ = make(T, int64(n)) }) shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) }) + testMakeInAppend(n) + var x uint64 = 1<<32 - 1 + shouldPanic("len out of range", func() { _ = make([]byte, x) }) + shouldPanic("cap out of range", func() { _ = make(T, 0, x) }) + testMakeInAppend(int(x)) } - - // Test make in append panics since the gc compiler optimizes makes in appends. - shouldPanic("len out of range", func() { _ = append(T{}, make(T, n)...) }) - shouldPanic("cap out of range", func() { _ = append(T{}, make(T, 0, n)...) }) - shouldPanic("len out of range", func() { _ = append(T{}, make(T, int64(n))...) }) - shouldPanic("cap out of range", func() { _ = append(T{}, make(T, 0, int64(n))...) }) } func shouldPanic(str string, f func()) { @@ -58,3 +65,21 @@ func shouldPanic(str string, f func()) { f() } + +// Test make in append panics since the gc compiler optimizes makes in appends. +func testMakeInAppend(n int) { + lengths := []int{0, 1} + for _, length := range lengths { + t := make(T, length) + shouldPanic("len out of range", func() { _ = append(t, make(T, n)...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, n)...) }) + shouldPanic("len out of range", func() { _ = append(t, make(T, int64(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int64(n))...) }) + shouldPanic("len out of range", func() { _ = append(t, make(T, uint64(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint64(n))...) }) + shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) }) + shouldPanic("len out of range", func() { _ = append(t, make(T, uint(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint(n))...) }) + } +} diff --git a/test/fixedbugs/issue5172.go b/test/fixedbugs/issue5172.go index a6acbd3d..0339935b 100644 --- a/test/fixedbugs/issue5172.go +++ b/test/fixedbugs/issue5172.go @@ -12,8 +12,15 @@ type foo struct { x bar // ERROR "undefined" } +type T struct{} + +func (t T) Bar() {} + func main() { var f foo - go f.bar() // GCCGO_ERROR "undefined" - defer f.bar() // GCCGO_ERROR "undefined" + go f.bar() // ERROR "undefined" + defer f.bar() // ERROR "undefined" + + t := T{1} // ERROR "too many values" + go t.Bar() } diff --git a/test/fixedbugs/issue6977.go b/test/fixedbugs/issue6977.go new file mode 100644 index 00000000..0f657eec --- /dev/null +++ b/test/fixedbugs/issue6977.go @@ -0,0 +1,40 @@ +// errorcheck + +// 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. + +package p + +import "io" + +// Alan's initial report. + +type I interface { f(); String() string } +type J interface { g(); String() string } + +type IJ1 = interface { I; J } +type IJ2 = interface { f(); g(); String() string } + +var _ = (*IJ1)(nil) == (*IJ2)(nil) // static assert that IJ1 and IJ2 are identical types + +// The canonical example. + +type ReadWriteCloser interface { io.ReadCloser; io.WriteCloser } + +// Some more cases. + +type M interface { m() } +type M32 interface { m() int32 } +type M64 interface { m() int64 } + +type U1 interface { m() } +type U2 interface { m(); M } +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" diff --git a/test/fixedbugs/issue7153.go b/test/fixedbugs/issue7153.go index f238f78e..66b13384 100644 --- a/test/fixedbugs/issue7153.go +++ b/test/fixedbugs/issue7153.go @@ -8,4 +8,4 @@ package p -var _ = []int{a: true, true} // ERROR "undefined: a" "cannot use true \(type bool\) as type int in array or slice literal" +var _ = []int{a: true, true} // ERROR "undefined: a" "cannot use true \(type untyped bool\) as type int in slice literal" diff --git a/test/fixedbugs/issue7310.go b/test/fixedbugs/issue7310.go index 1169fcfb..6829d5e1 100644 --- a/test/fixedbugs/issue7310.go +++ b/test/fixedbugs/issue7310.go @@ -11,5 +11,5 @@ package main func main() { _ = copy(nil, []int{}) // ERROR "use of untyped nil" _ = copy([]int{}, nil) // ERROR "use of untyped nil" - _ = 1+true // ERROR "cannot convert true" "mismatched types int and bool" + _ = 1 + true // ERROR "mismatched types untyped int and untyped bool" } diff --git a/test/fixedbugs/issue7921.go b/test/fixedbugs/issue7921.go index e19b1130..a8efc8dd 100644 --- a/test/fixedbugs/issue7921.go +++ b/test/fixedbugs/issue7921.go @@ -18,20 +18,20 @@ func bufferNotEscape() string { // can be stack-allocated. var b bytes.Buffer b.WriteString("123") - b.Write([]byte{'4'}) // ERROR "bufferNotEscape \[\]byte literal does not escape$" + b.Write([]byte{'4'}) // ERROR "\[\]byte literal 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 "bufferNoEscape2 xs does not escape$" - b := bytes.NewBuffer(make([]byte, 0, 64)) // ERROR "bufferNoEscape2 &bytes.Buffer literal does not escape$" "bufferNoEscape2 make\(\[\]byte, 0, 64\) does not escape$" "inlining call to bytes.NewBuffer$" +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$" for _, x := range xs { b.WriteString(x) } return b.Len() // ERROR "inlining call to bytes.\(\*Buffer\).Len$" } -func bufferNoEscape3(xs []string) string { // ERROR "bufferNoEscape3 xs does not escape$" - b := bytes.NewBuffer(make([]byte, 0, 64)) // ERROR "bufferNoEscape3 &bytes.Buffer literal does not escape$" "bufferNoEscape3 make\(\[\]byte, 0, 64\) does not escape$" "inlining call to bytes.NewBuffer$" +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$" for _, x := range xs { b.WriteString(x) b.WriteByte(',') @@ -47,11 +47,11 @@ func bufferNoEscape4() []byte { } func bufferNoEscape5() { // ERROR "can inline bufferNoEscape5$" - b := bytes.NewBuffer(make([]byte, 0, 128)) // ERROR "bufferNoEscape5 &bytes.Buffer literal does not escape$" "bufferNoEscape5 make\(\[\]byte, 0, 128\) does not escape$" "inlining call to bytes.NewBuffer$" + 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$" useBuffer(b) } //go:noinline -func useBuffer(b *bytes.Buffer) { // ERROR "useBuffer b does not escape$" +func useBuffer(b *bytes.Buffer) { // ERROR "b does not escape$" b.WriteString("1234") } diff --git a/test/fixedbugs/issue8047b.go b/test/fixedbugs/issue8047b.go index df902a52..5eaf9c5b 100644 --- a/test/fixedbugs/issue8047b.go +++ b/test/fixedbugs/issue8047b.go @@ -10,6 +10,10 @@ package main func main() { defer func() { + // This recover recovers the panic caused by the nil defer func + // g(). The original panic(1) was already aborted/replaced by this + // new panic, so when this recover is done, the program completes + // normally. recover() }() f() diff --git a/test/fixedbugs/issue8438.go b/test/fixedbugs/issue8438.go index b28025cd..3a4f193b 100644 --- a/test/fixedbugs/issue8438.go +++ b/test/fixedbugs/issue8438.go @@ -10,8 +10,8 @@ package main func main() { - _ = []byte{"foo"} // ERROR "cannot convert" - _ = []int{"foo"} // ERROR "cannot convert" - _ = []rune{"foo"} // ERROR "cannot convert" + _ = []byte{"foo"} // ERROR "cannot use" + _ = []int{"foo"} // ERROR "cannot use" + _ = []rune{"foo"} // ERROR "cannot use" _ = []string{"foo"} // OK } diff --git a/test/fixedbugs/issue8606.go b/test/fixedbugs/issue8606.go new file mode 100644 index 00000000..8122b1d2 --- /dev/null +++ b/test/fixedbugs/issue8606.go @@ -0,0 +1,50 @@ +// 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. + +// Check to make sure that we compare fields in order. See issue 8606. + +package main + +import "fmt" + +func main() { + type A [2]interface{} + type S struct{ x, y interface{} } + + for _, test := range []struct { + panic bool + a, b interface{} + }{ + {false, A{1, []byte{1}}, A{2, []byte{1}}}, + {true, A{[]byte{1}, 1}, A{[]byte{1}, 2}}, + {false, S{1, []byte{1}}, S{2, []byte{1}}}, + {true, S{[]byte{1}, 1}, S{[]byte{1}, 2}}, + {false, A{1, []byte{1}}, A{"2", []byte{1}}}, + {true, A{[]byte{1}, 1}, A{[]byte{1}, "2"}}, + {false, S{1, []byte{1}}, S{"2", []byte{1}}}, + {true, S{[]byte{1}, 1}, S{[]byte{1}, "2"}}, + } { + f := func() { + if test.a == test.b { + panic(fmt.Sprintf("values %#v and %#v should not be equal", test.a, test.b)) + } + } + if test.panic { + shouldPanic(fmt.Sprintf("comparing %#v and %#v did not panic", test.a, test.b), f) + } else { + f() // should not panic + } + } +} + +func shouldPanic(name string, f func()) { + defer func() { + if recover() == nil { + panic(name) + } + }() + f() +} diff --git a/test/fixedbugs/issue9355.go b/test/fixedbugs/issue9355.go index 9657e644..2498bf6a 100644 --- a/test/fixedbugs/issue9355.go +++ b/test/fixedbugs/issue9355.go @@ -8,6 +8,7 @@ package main import ( "fmt" + "io/ioutil" "os" "os/exec" "path/filepath" @@ -23,8 +24,15 @@ func main() { err := os.Chdir(filepath.Join("fixedbugs", "issue9355.dir")) check(err) - out := run("go", "tool", "compile", "-S", "a.go") - os.Remove("a.o") + f, err := ioutil.TempFile("", "issue9355-*.o") + if err != nil { + fmt.Println(err) + os.Exit(1) + } + f.Close() + + out := run("go", "tool", "compile", "-o", f.Name(), "-S", "a.go") + os.Remove(f.Name()) // 6g/8g print the offset as dec, but 5g/9g print the offset as hex. patterns := []string{ diff --git a/test/fixedbugs/issue9521.go b/test/fixedbugs/issue9521.go index 4e4a55f1..a33f0483 100644 --- a/test/fixedbugs/issue9521.go +++ b/test/fixedbugs/issue9521.go @@ -4,7 +4,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Test that an incorrect use of the blank identifer is caught. +// Test that an incorrect use of the blank identifier is caught. // Does not compile. package main diff --git a/test/fixedbugs/oldescape_issue12006.go b/test/fixedbugs/oldescape_issue12006.go deleted file mode 100644 index 0697f58b..00000000 --- a/test/fixedbugs/oldescape_issue12006.go +++ /dev/null @@ -1,174 +0,0 @@ -// errorcheck -0 -m -l -newescape=false - -// Copyright 2015 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. - -// Test escape analysis through ... parameters. - -package foo - -func FooN(vals ...*int) (s int) { // ERROR "FooN vals does not escape" - for _, v := range vals { - s += *v - } - return s -} - -// Append forces heap allocation and copies entries in vals to heap, therefore they escape to heap. -func FooNx(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param content: vals" - vals = append(vals, x) - return FooN(vals...) -} - -var sink []*int - -func FooNy(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param: vals" "leaking param content: vals" - vals = append(vals, x) - sink = vals - return FooN(vals...) -} - -func FooNz(vals ...*int) (s int) { // ERROR "leaking param: vals" - sink = vals - return FooN(vals...) -} - -func TFooN() { - for i := 0; i < 1000; i++ { - var i, j int - FooN(&i, &j) // ERROR "TFooN ... argument does not escape" - } -} - -func TFooNx() { - for i := 0; i < 1000; i++ { - var i, j, k int // ERROR "moved to heap: i" "moved to heap: j" "moved to heap: k" - FooNx(&k, &i, &j) // ERROR "TFooNx ... argument does not escape" - } -} - -func TFooNy() { - for i := 0; i < 1000; i++ { - var i, j, k int // ERROR "moved to heap: i" "moved to heap: j" "moved to heap: k" - FooNy(&k, &i, &j) // ERROR "... argument escapes to heap" - } -} - -func TFooNz() { - for i := 0; i < 1000; i++ { - var i, j int // ERROR "moved to heap: i" "moved to heap: j" - FooNz(&i, &j) // ERROR "... argument escapes to heap" - } -} - -var isink *int32 - -func FooI(args ...interface{}) { // ERROR "leaking param content: args" - for i := 0; i < len(args); i++ { - switch x := args[i].(type) { - case nil: - println("is nil") - case int32: - println("is int32") - case *int32: - println("is *int32") - isink = x - case string: - println("is string") - } - } -} - -func TFooI() { - a := int32(1) // ERROR "moved to heap: a" - b := "cat" - c := &a - FooI(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooI ... argument does not escape" -} - -func FooJ(args ...interface{}) *int32 { // ERROR "leaking param: args to result ~r1 level=1" - for i := 0; i < len(args); i++ { - switch x := args[i].(type) { - case nil: - println("is nil") - case int32: - println("is int32") - case *int32: - println("is *int32") - return x - case string: - println("is string") - } - } - return nil -} - -func TFooJ1() { - a := int32(1) - b := "cat" - c := &a - FooJ(a, b, c) // ERROR "TFooJ1 a does not escape" "TFooJ1 b does not escape" "TFooJ1 c does not escape" "TFooJ1 ... argument does not escape" -} - -func TFooJ2() { - a := int32(1) // ERROR "moved to heap: a" - b := "cat" - c := &a - isink = FooJ(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "c escapes to heap" "TFooJ2 ... argument does not escape" -} - -type fakeSlice struct { - l int - a *[4]interface{} -} - -func FooK(args fakeSlice) *int32 { // ERROR "leaking param: args to result ~r1 level=1" - for i := 0; i < args.l; i++ { - switch x := (*args.a)[i].(type) { - case nil: - println("is nil") - case int32: - println("is int32") - case *int32: - println("is *int32") - return x - case string: - println("is string") - } - } - return nil -} - -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" "c escapes to heap" "TFooK2 &\[4\]interface {} literal does not escape" - isink = FooK(fs) -} - -func FooL(args []interface{}) *int32 { // ERROR "leaking param: args to result ~r1 level=1" - for i := 0; i < len(args); i++ { - switch x := args[i].(type) { - case nil: - println("is nil") - case int32: - println("is int32") - case *int32: - println("is *int32") - return x - case string: - println("is string") - } - } - return nil -} - -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" "c escapes to heap" "TFooL2 \[\]interface {} literal does not escape" - isink = FooL(s) -} diff --git a/test/fixedbugs/oldescape_issue17318.go b/test/fixedbugs/oldescape_issue17318.go deleted file mode 100644 index 10084ba8..00000000 --- a/test/fixedbugs/oldescape_issue17318.go +++ /dev/null @@ -1,47 +0,0 @@ -// errorcheck -0 -N -m -l -newescape=false - -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The escape analyzer needs to run till its root set settles -// (this is not that often, it turns out). -// This test is likely to become stale because the leak depends -// on a spurious-escape bug -- return an interface as a named -// output parameter appears to cause the called closure to escape, -// where returning it as a regular type does not. - -package main - -import ( - "fmt" -) - -type closure func(i, j int) ent - -type ent int - -func (e ent) String() string { - return fmt.Sprintf("%d", int(e)) // ERROR "ent.String ... argument does not escape$" "int\(e\) escapes to heap$" -} - -//go:noinline -func foo(ops closure, j int) (err fmt.Stringer) { // ERROR "leaking param: ops$" "leaking param: ops to result err level=0$" - enqueue := func(i int) fmt.Stringer { // ERROR "func literal escapes to heap$" - return ops(i, j) // ERROR "ops\(i, j\) escapes to heap$" - } - err = enqueue(4) - if err != nil { - return err - } - return // return result of enqueue, a fmt.Stringer -} - -func main() { - // 3 identical functions, to get different escape behavior. - f := func(i, j int) ent { // ERROR "func literal escapes to heap$" - return ent(i + j) - } - i := foo(f, 3).(ent) - fmt.Printf("foo(f,3)=%d\n", int(i)) // ERROR "int\(i\) escapes to heap$" "main ... argument does not escape$" -} diff --git a/test/goprint.go b/test/goprint.go index 57eeac53..d44b2590 100644 --- a/test/goprint.go +++ b/test/goprint.go @@ -9,13 +9,24 @@ package main import ( + "log" "runtime" "time" ) func main() { + numg0 := runtime.NumGoroutine() + deadline := time.Now().Add(10 * time.Second) go println(42, true, false, true, 1.5, "world", (chan int)(nil), []int(nil), (map[string]int)(nil), (func())(nil), byte(255)) - for runtime.NumGoroutine() > 1 { - time.Sleep(10*time.Millisecond) + for { + numg := runtime.NumGoroutine() + if numg > numg0 { + if time.Now().After(deadline) { + log.Fatalf("%d goroutines > initial %d after deadline", numg, numg0) + } + runtime.Gosched() + continue + } + break } } diff --git a/test/index.go b/test/index.go index d73d137d..91195ad6 100644 --- a/test/index.go +++ b/test/index.go @@ -251,7 +251,7 @@ func main() { if c == "" && (i == "fgood" || i == "fbad") { return } - // Integral float constat is ok. + // Integral float constant is ok. if c == "c" && n == "" && i == "fgood" { if pass == 0 { fmt.Fprintf(b, "\tuse(%s[%s])\n", pae, cni) diff --git a/test/initempty.go b/test/initempty.go new file mode 100644 index 00000000..60bd9fb3 --- /dev/null +++ b/test/initempty.go @@ -0,0 +1,40 @@ +// run + +// 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. + +// Test that empty init functions are skipped. + +package main + +import _ "unsafe" // for go:linkname + +type initTask struct { + state uintptr + ndeps uintptr + nfns uintptr +} + +//go:linkname main_inittask main..inittask +var main_inittask initTask + +func main() { + if nfns := main_inittask.nfns; nfns != 0 { + println(nfns) + panic("unexpected init funcs") + } +} + +func init() { +} + +func init() { + if false { + } +} + +func init() { + for false { + } +} diff --git a/test/inline.go b/test/inline.go index 7e055170..0b3ad55d 100644 --- a/test/inline.go +++ b/test/inline.go @@ -95,15 +95,15 @@ func p() int { } func q(x int) int { - foo := func() int { return x * 2 } // ERROR "can inline q.func1" "q func literal does not escape" + foo := func() int { return x * 2 } // ERROR "can inline q.func1" "func literal does not escape" return foo() // ERROR "inlining call to q.func1" } func r(z int) int { - foo := func(x int) int { // ERROR "can inline r.func1" "r func literal does not escape" + foo := func(x int) int { // ERROR "can inline r.func1" "func literal does not escape" return x + z } - bar := func(x int) int { // ERROR "r func literal does not escape" + bar := func(x int) int { // ERROR "func literal does not escape" return x + func(y int) int { // ERROR "can inline r.func2.1" return 2*y + x*z }(x) // ERROR "inlining call to r.func2.1" @@ -112,7 +112,7 @@ func r(z int) int { } func s0(x int) int { - foo := func() { // ERROR "can inline s0.func1" "s0 func literal does not escape" + foo := func() { // ERROR "can inline s0.func1" "func literal does not escape" x = x + 1 } foo() // ERROR "inlining call to s0.func1" @@ -120,7 +120,7 @@ func s0(x int) int { } func s1(x int) int { - foo := func() int { // ERROR "can inline s1.func1" "s1 func literal does not escape" + foo := func() int { // ERROR "can inline s1.func1" "func literal does not escape" return x } x = x + 1 @@ -145,7 +145,7 @@ func switchBreak(x, y int) int { } // can't currently inline functions with a type switch -func switchType(x interface{}) int { // ERROR "switchType x does not escape" +func switchType(x interface{}) int { // ERROR "x does not escape" switch x.(type) { case int: return x.(int) @@ -180,3 +180,21 @@ func (T) meth2(int, int) { // not inlineable - has 2 calls. runtime.GC() runtime.GC() } + +// Issue #29737 - make sure we can do inlining for a chain of recursive functions +func ee() { // ERROR "can inline ee" + ff(100) // ERROR "inlining call to ff" "inlining call to gg" "inlining call to hh" +} + +func ff(x int) { // ERROR "can inline ff" + if x < 0 { + return + } + gg(x - 1) +} +func gg(x int) { // ERROR "can inline gg" + hh(x - 1) +} +func hh(x int) { // ERROR "can inline hh" + ff(x - 1) // ERROR "inlining call to ff" // ERROR "inlining call to gg" +} diff --git a/test/inline_big.go b/test/inline_big.go index c4af15b4..68e1101d 100644 --- a/test/inline_big.go +++ b/test/inline_big.go @@ -9,18 +9,18 @@ package foo -func small(a []int) int { // ERROR "can inline small as:.*" "small a does not escape" +func small(a []int) int { // ERROR "can inline small with cost .* as:.*" "a does not escape" // Cost 16 body (need cost < 20). // See cmd/compile/internal/gc/inl.go:inlineBigFunction* return a[0] + a[1] + a[2] + a[3] } -func medium(a []int) int { // ERROR "can inline medium as:.*" "medium a does not escape" +func medium(a []int) int { // ERROR "can inline medium with cost .* as:.*" "a does not escape" // Cost 32 body (need cost > 20 and cost < 80). // See cmd/compile/internal/gc/inl.go:inlineBigFunction* return a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] } -func f(a []int) int { // ERROR "cannot inline f:.*" "f a does not escape" +func f(a []int) int { // ERROR "cannot inline f:.*" "a does not escape" // Add lots of nodes to f's body. We need >5000. // See cmd/compile/internal/gc/inl.go:inlineBigFunction* a[0] = 0 diff --git a/test/interface/embed3.dir/embed0.go b/test/interface/embed3.dir/embed0.go new file mode 100644 index 00000000..614609e7 --- /dev/null +++ b/test/interface/embed3.dir/embed0.go @@ -0,0 +1,21 @@ +// 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. + +package p + +type I1 interface { + Foo(int) +} + +type I2 interface { + foo(int) +} + +type M1 int + +func (M1) foo() {} + +type M2 int + +func (M2) foo(int) {} diff --git a/test/interface/embed3.dir/embed1.go b/test/interface/embed3.dir/embed1.go new file mode 100644 index 00000000..d042482e --- /dev/null +++ b/test/interface/embed3.dir/embed1.go @@ -0,0 +1,78 @@ +// 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. + +package main + +import "./embed0" + +type X1 struct{} + +func (X1) Foo() {} + +type X2 struct{} + +func (X2) foo() {} + +type X3 struct{} + +func (X3) foo(int) {} + +type X4 struct{ p.M1 } + +type X5 struct{ p.M1 } + +func (X5) foo(int) {} + +type X6 struct{ p.M2 } + +type X7 struct{ p.M2 } + +func (X7) foo() {} + +type X8 struct{ p.M2 } + +func (X8) foo(int) {} + +func main() { + var i1 interface{} = X1{} + check(func() { _ = i1.(p.I1) }, "interface conversion: main.X1 is not p.I1: missing method Foo") + + var i2 interface{} = X2{} + check(func() { _ = i2.(p.I2) }, "interface conversion: main.X2 is not p.I2: missing method foo") + + var i3 interface{} = X3{} + check(func() { _ = i3.(p.I2) }, "interface conversion: main.X3 is not p.I2: missing method foo") + + var i4 interface{} = X4{} + check(func() { _ = i4.(p.I2) }, "interface conversion: main.X4 is not p.I2: missing method foo") + + var i5 interface{} = X5{} + check(func() { _ = i5.(p.I2) }, "interface conversion: main.X5 is not p.I2: missing method foo") + + var i6 interface{} = X6{} + check(func() { _ = i6.(p.I2) }, "") + + var i7 interface{} = X7{} + check(func() { _ = i7.(p.I2) }, "") + + var i8 interface{} = X8{} + check(func() { _ = i8.(p.I2) }, "") +} + +func check(f func(), msg string) { + defer func() { + v := recover() + if v == nil { + if msg == "" { + return + } + panic("did not panic") + } + got := v.(error).Error() + if msg != got { + panic("want '" + msg + "', got '" + got + "'") + } + }() + f() +} diff --git a/test/interface/embed3.go b/test/interface/embed3.go new file mode 100644 index 00000000..af6f1341 --- /dev/null +++ b/test/interface/embed3.go @@ -0,0 +1,7 @@ +// rundir + +// 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. + +package ignored diff --git a/test/intrinsic_atomic.go b/test/intrinsic_atomic.go index a90056e1..61911b7a 100644 --- a/test/intrinsic_atomic.go +++ b/test/intrinsic_atomic.go @@ -1,5 +1,5 @@ // errorcheck -0 -d=ssa/intrinsics/debug -// +build amd64 arm64 mips mipsle mips64 mips64le ppc64 ppc64le s390x +// +build amd64 arm64 mips mipsle mips64 mips64le ppc64 ppc64le riscv64 s390x // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/ken/modconst.go b/test/ken/modconst.go index d88cf100..c27bf64b 100644 --- a/test/ken/modconst.go +++ b/test/ken/modconst.go @@ -4,7 +4,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Test integer modulus by contstants. +// Test integer modulus by constants. package main diff --git a/test/linkmain_run.go b/test/linkmain_run.go index 68d53e8c..077f7ee9 100644 --- a/test/linkmain_run.go +++ b/test/linkmain_run.go @@ -11,21 +11,21 @@ package main import ( "fmt" + "io/ioutil" "os" "os/exec" + "path/filepath" "strings" ) +var tmpDir string + func cleanup() { - os.Remove("linkmain.o") - os.Remove("linkmain.a") - os.Remove("linkmain1.o") - os.Remove("linkmain1.a") - os.Remove("linkmain.exe") + os.RemoveAll(tmpDir) } -func run(cmdline string) { - args := strings.Fields(cmdline) +func run(cmdline ...string) { + args := strings.Fields(strings.Join(cmdline, " ")) cmd := exec.Command(args[0], args[1:]...) out, err := cmd.CombinedOutput() if err != nil { @@ -37,8 +37,8 @@ func run(cmdline string) { } } -func runFail(cmdline string) { - args := strings.Fields(cmdline) +func runFail(cmdline ...string) { + args := strings.Fields(strings.Join(cmdline, " ")) cmd := exec.Command(args[0], args[1:]...) out, err := cmd.CombinedOutput() if err == nil { @@ -51,16 +51,26 @@ func runFail(cmdline string) { } func main() { + var err error + tmpDir, err = ioutil.TempDir("", "") + if err != nil { + fmt.Println(err) + os.Exit(1) + } + tmp := func(name string) string { + return filepath.Join(tmpDir, name) + } + // helloworld.go is package main - run("go tool compile -o linkmain.o helloworld.go") - run("go tool compile -pack -o linkmain.a helloworld.go") - run("go tool link -o linkmain.exe linkmain.o") - run("go tool link -o linkmain.exe linkmain.a") + run("go tool compile -o", tmp("linkmain.o"), "helloworld.go") + run("go tool compile -pack -o", tmp("linkmain.a"), "helloworld.go") + run("go tool link -o", tmp("linkmain.exe"), tmp("linkmain.o")) + run("go tool link -o", tmp("linkmain.exe"), tmp("linkmain.a")) // linkmain.go is not - run("go tool compile -o linkmain1.o linkmain.go") - run("go tool compile -pack -o linkmain1.a linkmain.go") - runFail("go tool link -o linkmain.exe linkmain1.o") - runFail("go tool link -o linkmain.exe linkmain1.a") + run("go tool compile -o", tmp("linkmain1.o"), "linkmain.go") + run("go tool compile -pack -o", tmp("linkmain1.a"), "linkmain.go") + runFail("go tool link -o", tmp("linkmain.exe"), tmp("linkmain1.o")) + runFail("go tool link -o", tmp("linkmain.exe"), tmp("linkmain1.a")) cleanup() } diff --git a/test/linkname.dir/linkname1.go b/test/linkname.dir/linkname1.go index 9c61522f..c61a0d7d 100644 --- a/test/linkname.dir/linkname1.go +++ b/test/linkname.dir/linkname1.go @@ -1,6 +1,6 @@ package x -func indexByte(xs []byte, b byte) int { // ERROR "indexByte xs does not escape" +func indexByte(xs []byte, b byte) int { // ERROR "xs does not escape" for i, x := range xs { if x == b { return i diff --git a/test/linkname.go b/test/linkname.go index 8e79b51b..c94a113c 100644 --- a/test/linkname.go +++ b/test/linkname.go @@ -1,4 +1,4 @@ -// errorcheckandrundir -0 -m -l=4 -newescape=true +// errorcheckandrundir -0 -m -l=4 // Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/linkx.go b/test/linkx.go index 20b8c773..4f85b241 100644 --- a/test/linkx.go +++ b/test/linkx.go @@ -14,10 +14,25 @@ import "fmt" var tbd string var overwrite string = "dibs" +var tbdcopy = tbd +var overwritecopy = overwrite +var arraycopy = [2]string{tbd, overwrite} + var b bool var x int func main() { fmt.Println(tbd) + fmt.Println(tbdcopy) + fmt.Println(arraycopy[0]) + fmt.Println(overwrite) + fmt.Println(overwritecopy) + fmt.Println(arraycopy[1]) + + // Check non-string symbols are not overwritten. + // This also make them used. + if b || x != 0 { + panic("b or x overwritten") + } } diff --git a/test/linkx_run.go b/test/linkx_run.go index ca9d3161..f25053bf 100644 --- a/test/linkx_run.go +++ b/test/linkx_run.go @@ -36,7 +36,7 @@ func test(sep string) { os.Exit(1) } - want := "hello\ntrumped\n" + want := "hello\nhello\nhello\ntrumped\ntrumped\ntrumped\n" got := out.String() if got != want { fmt.Printf("got %q want %q\n", got, want) diff --git a/test/live.go b/test/live.go index ec511937..3df7ab01 100644 --- a/test/live.go +++ b/test/live.go @@ -1,5 +1,6 @@ // errorcheckwithauto -0 -l -live -wb=0 -d=ssa/insert_resched_checks/off // +build !ppc64,!ppc64le + // ppc64 needs a better tighten pass to make f18 pass // rescheduling checks need to be turned off because there are some live variables across the inserted check call @@ -367,16 +368,19 @@ func f24() { m2[[2]string{"x", "y"}] = nil } -// defer should not cause spurious ambiguously live variables - +// Non-open-coded defers should not cause autotmps. (Open-coded defers do create extra autotmps). func f25(b bool) { - defer g25() + for i := 0; i < 2; i++ { + // Put in loop to make sure defer is not open-coded + defer g25() + } if b { return } var x string x = g14() printstring(x) + return } func g25() @@ -417,7 +421,8 @@ func f27defer(b bool) { defer call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{" } defer call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{" - printnl() + printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ .autotmp_[0-9]+" + return // ERROR "live at call to call27: .autotmp_[0-9]+" } // and newproc (go) escapes to the heap @@ -659,7 +664,7 @@ func bad40() { func good40() { ret := T40{} // ERROR "stack object ret T40$" - ret.m = make(map[int]int) // ERROR "live at call to fastrand: .autotmp_[0-9]+ ret$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$" + ret.m = make(map[int]int) // ERROR "live at call to fastrand: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$" t := &ret printnl() // ERROR "live at call to printnl: ret$" // Note: ret is live at the printnl because the compiler moves &ret @@ -687,12 +692,12 @@ type R struct{ *T } // ERRORAUTO "live at entry to \(\*R\)\.Foo: \.this ptr" "li // In particular, at printint r must be live. func f41(p, q *int) (r *int) { // ERROR "live at entry to f41: p q$" r = p - defer func() { // ERROR "live at call to deferprocStack: q r$" "live at call to deferreturn: r$" + defer func() { recover() }() - printint(0) // ERROR "live at call to printint: q r$" + printint(0) // ERROR "live at call to printint: q r .autotmp_[0-9]+$" r = q - return // ERROR "live at call to deferreturn: r$" + return // ERROR "live at call to f41.func1: r .autotmp_[0-9]+$" } func f42() { @@ -704,3 +709,14 @@ func f42() { //go:noescape func f43(a []*int) + +// Assigning to a sub-element that makes up an entire local variable +// should clobber that variable. +func f44(f func() [2]*int) interface{} { // ERROR "live at entry to f44: f" + type T struct { + s [1][2]*int + } + ret := T{} + ret.s[0] = f() + return ret // ERROR "stack object .autotmp_5 T" +} diff --git a/test/live2.go b/test/live2.go index cea312f0..83a6cb7d 100644 --- a/test/live2.go +++ b/test/live2.go @@ -27,14 +27,14 @@ func newT40() *T40 { } func bad40() { - t := newT40() // ERROR "live at call to makemap: ret$" "stack object ret T40$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$" + t := newT40() // ERROR "stack object ret T40$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$" printnl() // ERROR "live at call to printnl: ret$" useT40(t) } func good40() { ret := T40{} // ERROR "stack object ret T40$" - ret.m = make(map[int]int, 42) // ERROR "live at call to makemap: ret$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$" + ret.m = make(map[int]int, 42) // ERROR "stack object .autotmp_[0-9]+ map.hdr\[int\]int$" t := &ret printnl() // ERROR "live at call to printnl: ret$" useT40(t) diff --git a/test/live_syscall.go b/test/live_syscall.go index 2d1ef14d..b920ff68 100644 --- a/test/live_syscall.go +++ b/test/live_syscall.go @@ -15,7 +15,7 @@ import ( "unsafe" ) -func f(uintptr) // ERROR "f assuming arg#1 is unsafe uintptr" +func f(uintptr) // ERROR "assuming arg#1 is unsafe uintptr" func g() { // ERROR "can inline g" var t int diff --git a/test/loopbce.go b/test/loopbce.go index e0a6463c..f0c9bd0f 100644 --- a/test/loopbce.go +++ b/test/loopbce.go @@ -257,6 +257,39 @@ func k5(a [100]int) [100]int { return a } +func d1(a [100]int) [100]int { + for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$" + for j := 0; j < i; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$" + a[j] = 0 // ERROR "Proved IsInBounds$" + a[j+1] = 0 // FIXME: this boundcheck should be eliminated + a[j+2] = 0 + } + } + return a +} + +func d2(a [100]int) [100]int { + for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$" + for j := 0; i > j; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$" + a[j] = 0 // ERROR "Proved IsInBounds$" + a[j+1] = 0 // FIXME: this boundcheck should be eliminated + a[j+2] = 0 + } + } + return a +} + +func d3(a [100]int) [100]int { + for i := 0; i <= 99; i++ { // ERROR "Induction variable: limits \[0,99\], increment 1$" + for j := 0; j <= i-1; j++ { // ERROR "Induction variable: limits \[0,\?\], increment 1$" + a[j] = 0 // ERROR "Proved IsInBounds$" + a[j+1] = 0 // ERROR "Proved IsInBounds$" + a[j+2] = 0 + } + } + return a +} + func nobce1() { // tests overflow of max-min a := int64(9223372036854774057) diff --git a/test/makechan.go b/test/makechan.go index 0ac38c4b..6608620d 100644 --- a/test/makechan.go +++ b/test/makechan.go @@ -22,12 +22,6 @@ func main() { sink = make(T, 1.0) sink = make(T, float32(1.0)) // ERROR "non-integer buffer argument in make.*" sink = make(T, float64(1.0)) // ERROR "non-integer buffer argument in make.*" - sink = make(T, 1.0) - sink = make(T, float32(1.0)) // ERROR "non-integer buffer argument in make.*" - sink = make(T, float64(1.0)) // ERROR "non-integer buffer argument in make.*" - sink = make(T, 1+0i) - sink = make(T, complex64(1+0i)) // ERROR "non-integer buffer argument in make.*" - sink = make(T, complex128(1+0i)) // ERROR "non-integer buffer argument in make.*" sink = make(T, 1+0i) sink = make(T, complex64(1+0i)) // ERROR "non-integer buffer argument in make.*" sink = make(T, complex128(1+0i)) // ERROR "non-integer buffer argument in make.*" diff --git a/test/makemap.go b/test/makemap.go index d19e6c34..63998d70 100644 --- a/test/makemap.go +++ b/test/makemap.go @@ -28,12 +28,6 @@ func main() { sink = make(T, 1.0) sink = make(T, float32(1.0)) // ERROR "non-integer size argument in make.*" sink = make(T, float64(1.0)) // ERROR "non-integer size argument in make.*" - sink = make(T, 1.0) - sink = make(T, float32(1.0)) // ERROR "non-integer size argument in make.*" - sink = make(T, float64(1.0)) // ERROR "non-integer size argument in make.*" - sink = make(T, 1+0i) - sink = make(T, complex64(1+0i)) // ERROR "non-integer size argument in make.*" - sink = make(T, complex128(1+0i)) // ERROR "non-integer size argument in make.*" sink = make(T, 1+0i) sink = make(T, complex64(1+0i)) // ERROR "non-integer size argument in make.*" sink = make(T, complex128(1+0i)) // ERROR "non-integer size argument in make.*" diff --git a/test/makeslice.go b/test/makeslice.go new file mode 100644 index 00000000..0ffecd7c --- /dev/null +++ b/test/makeslice.go @@ -0,0 +1,149 @@ +// run + +// Copyright 2013 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 ( + "strings" + "unsafe" +) + +func main() { + n := -1 + testInts(uint64(n)) + testBytes(uint64(n)) + + var t *byte + if unsafe.Sizeof(t) == 8 { + // Test mem > maxAlloc + testInts(1 << 59) + + // Test elem.size*cap overflow + testInts(1<<63 - 1) + + testInts(1<<64 - 1) + testBytes(1<<64 - 1) + } else { + testInts(1<<31 - 1) + + // Test elem.size*cap overflow + testInts(1<<32 - 1) + testBytes(1<<32 - 1) + } +} + +func shouldPanic(str string, f func()) { + defer func() { + err := recover() + if err == nil { + panic("did not panic") + } + s := err.(error).Error() + if !strings.Contains(s, str) { + panic("got panic " + s + ", want " + str) + } + }() + + f() +} + +func testInts(n uint64) { + testMakeInts(n) + testMakeCopyInts(n) + testMakeInAppendInts(n) +} + +func testBytes(n uint64) { + testMakeBytes(n) + testMakeCopyBytes(n) + testMakeInAppendBytes(n) +} + +// Test make panics for given length or capacity n. +func testMakeInts(n uint64) { + type T []int + shouldPanic("len out of range", func() { _ = make(T, int(n)) }) + shouldPanic("cap out of range", func() { _ = make(T, 0, int(n)) }) + shouldPanic("len out of range", func() { _ = make(T, uint(n)) }) + shouldPanic("cap out of range", func() { _ = make(T, 0, uint(n)) }) + shouldPanic("len out of range", func() { _ = make(T, int64(n)) }) + shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) }) + shouldPanic("len out of range", func() { _ = make(T, uint64(n)) }) + shouldPanic("cap out of range", func() { _ = make(T, 0, uint64(n)) }) +} + +func testMakeBytes(n uint64) { + type T []byte + shouldPanic("len out of range", func() { _ = make(T, int(n)) }) + shouldPanic("cap out of range", func() { _ = make(T, 0, int(n)) }) + shouldPanic("len out of range", func() { _ = make(T, uint(n)) }) + shouldPanic("cap out of range", func() { _ = make(T, 0, uint(n)) }) + shouldPanic("len out of range", func() { _ = make(T, int64(n)) }) + shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) }) + shouldPanic("len out of range", func() { _ = make(T, uint64(n)) }) + shouldPanic("cap out of range", func() { _ = make(T, 0, uint64(n)) }) +} + +// Test make+copy panics since the gc compiler optimizes these +// to runtime.makeslicecopy calls. +func testMakeCopyInts(n uint64) { + type T []int + var c = make(T, 8) + shouldPanic("len out of range", func() { x := make(T, int(n)); copy(x, c) }) + shouldPanic("cap out of range", func() { x := make(T, 0, int(n)); copy(x, c) }) + shouldPanic("len out of range", func() { x := make(T, uint(n)); copy(x, c) }) + shouldPanic("cap out of range", func() { x := make(T, 0, uint(n)); copy(x, c) }) + shouldPanic("len out of range", func() { x := make(T, int64(n)); copy(x, c) }) + shouldPanic("cap out of range", func() { x := make(T, 0, int64(n)); copy(x, c) }) + shouldPanic("len out of range", func() { x := make(T, uint64(n)); copy(x, c) }) + shouldPanic("cap out of range", func() { x := make(T, 0, uint64(n)); copy(x, c) }) +} + +func testMakeCopyBytes(n uint64) { + type T []byte + var c = make(T, 8) + shouldPanic("len out of range", func() { x := make(T, int(n)); copy(x, c) }) + shouldPanic("cap out of range", func() { x := make(T, 0, int(n)); copy(x, c) }) + shouldPanic("len out of range", func() { x := make(T, uint(n)); copy(x, c) }) + shouldPanic("cap out of range", func() { x := make(T, 0, uint(n)); copy(x, c) }) + shouldPanic("len out of range", func() { x := make(T, int64(n)); copy(x, c) }) + shouldPanic("cap out of range", func() { x := make(T, 0, int64(n)); copy(x, c) }) + shouldPanic("len out of range", func() { x := make(T, uint64(n)); copy(x, c) }) + shouldPanic("cap out of range", func() { x := make(T, 0, uint64(n)); copy(x, c) }) +} + +// Test make in append panics for int slices since the gc compiler optimizes makes in appends. +func testMakeInAppendInts(n uint64) { + type T []int + for _, length := range []int{0, 1} { + t := make(T, length) + shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) }) + shouldPanic("len out of range", func() { _ = append(t, make(T, int64(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int64(n))...) }) + shouldPanic("len out of range", func() { _ = append(t, make(T, uint64(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint64(n))...) }) + shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) }) + shouldPanic("len out of range", func() { _ = append(t, make(T, uint(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint(n))...) }) + } +} + +func testMakeInAppendBytes(n uint64) { + type T []byte + for _, length := range []int{0, 1} { + t := make(T, length) + shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) }) + shouldPanic("len out of range", func() { _ = append(t, make(T, uint(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint(n))...) }) + shouldPanic("len out of range", func() { _ = append(t, make(T, int64(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int64(n))...) }) + shouldPanic("len out of range", func() { _ = append(t, make(T, uint64(n))...) }) + shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint64(n))...) }) + } +} diff --git a/test/nosplit.go b/test/nosplit.go index 266e6077..a3f2a9fb 100644 --- a/test/nosplit.go +++ b/test/nosplit.go @@ -283,6 +283,9 @@ TestCases: case "amd64": ptrSize = 8 fmt.Fprintf(&buf, "#define REGISTER AX\n") + case "riscv64": + ptrSize = 8 + fmt.Fprintf(&buf, "#define REGISTER A0\n") case "s390x": ptrSize = 8 fmt.Fprintf(&buf, "#define REGISTER R10\n") @@ -309,17 +312,17 @@ TestCases: name := m[1] size, _ := strconv.Atoi(m[2]) - // The limit was originally 128 but is now 752 (880-128). + // The limit was originally 128 but is now 800 (928-128). // Instead of rewriting the test cases above, adjust // the first stack frame to use up the extra bytes. if i == 0 { - size += (880 - 128) - 128 + size += (928 - 128) - 128 // Noopt builds have a larger stackguard. // See ../src/cmd/dist/buildruntime.go:stackGuardMultiplier // This increase is included in objabi.StackGuard for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") { if s == "-N" { - size += 880 + size += 928 } } } diff --git a/test/nowritebarrier.go b/test/nowritebarrier.go index 64666fa5..654f16d0 100644 --- a/test/nowritebarrier.go +++ b/test/nowritebarrier.go @@ -67,6 +67,7 @@ func d2() { d3() } +//go:noinline func d3() { x.f = y // ERROR "write barrier prohibited by caller" d4() diff --git a/test/oldescape2.go b/test/oldescape2.go deleted file mode 100644 index 864a9561..00000000 --- a/test/oldescape2.go +++ /dev/null @@ -1,1847 +0,0 @@ -// errorcheck -0 -m -l -newescape=false - -// Copyright 2010 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. - -// Test, using compiler diagnostic flags, that the escape analysis is working. -// Compiles but does not run. Inlining is disabled. - -// escape2n.go contains all the same tests but compiles with -N. - -package foo - -import ( - "fmt" - "unsafe" -) - -var gxx *int - -func foo1(x int) { // ERROR "moved to heap: x$" - gxx = &x -} - -func foo2(yy *int) { // ERROR "leaking param: yy$" - gxx = yy -} - -func foo3(x int) *int { // ERROR "moved to heap: x$" - return &x -} - -type T *T - -func foo3b(t T) { // ERROR "leaking param: t$" - *t = t -} - -// xx isn't going anywhere, so use of yy is ok -func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$" - xx = yy -} - -// xx isn't going anywhere, so taking address of yy is ok -func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$" - xx = &yy -} - -func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$" - *xx = yy -} - -func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$" - **xx = *yy -} - -func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$" - xx = yy - return *xx -} - -func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$" - xx = yy - return xx -} - -func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$" - *xx = *yy -} - -func foo11() int { - x, y := 0, 42 - xx := &x - yy := &y - *xx = *yy - return x -} - -var xxx **int - -func foo12(yyy **int) { // ERROR "leaking param: yyy$" - xxx = yyy -} - -// Must treat yyy as leaking because *yyy leaks, and the escape analysis -// summaries in exported metadata do not distinguish these two cases. -func foo13(yyy **int) { // ERROR "leaking param content: yyy$" - *xxx = *yyy -} - -func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$" - **xxx = **yyy -} - -func foo15(yy *int) { // ERROR "moved to heap: yy$" - xxx = &yy -} - -func foo16(yy *int) { // ERROR "leaking param: yy$" - *xxx = yy -} - -func foo17(yy *int) { // ERROR "foo17 yy does not escape$" - **xxx = *yy -} - -func foo18(y int) { // ERROR "moved to heap: y$" - *xxx = &y -} - -func foo19(y int) { - **xxx = y -} - -type Bar struct { - i int - ii *int -} - -func NewBar() *Bar { - return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" -} - -func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$" - return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" -} - -func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$" - return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$" -} - -func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$" - return *(b.ii) -} - -func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$" - return &b.i -} - -func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$" - return b.ii -} - -func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$" - return b.ii -} - -func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$" - v := 0 // ERROR "moved to heap: v$" - b.ii = &v - return b.ii -} - -func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$" - v := 0 // ERROR "moved to heap: v$" - b.ii = &v - return b.ii -} - -func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$" - v := 0 - b.ii = &v - return b.i -} - -func goLeak(b *Bar) { // ERROR "leaking param: b$" - go b.NoLeak() -} - -type Bar2 struct { - i [12]int - ii []int -} - -func NewBar2() *Bar2 { - return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$" -} - -func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$" - return b.i[0] -} - -func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$" - return b.i[:] -} - -func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$" - return b.ii[0:1] -} - -func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$" - return b.i -} - -func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$" - b.ii = b.i[0:4] -} - -func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$" - var buf []int - buf = b.i[0:] - b.ii = buf -} - -func foo21() func() int { - x := 42 - return func() int { // ERROR "func literal escapes to heap$" - return x - } -} - -func foo21a() func() int { - x := 42 // ERROR "moved to heap: x$" - return func() int { // ERROR "func literal escapes to heap$" - x++ - return x - } -} - -func foo22() int { - x := 42 - return func() int { // ERROR "foo22 func literal does not escape$" - return x - }() -} - -func foo23(x int) func() int { - return func() int { // ERROR "func literal escapes to heap$" - return x - } -} - -func foo23a(x int) func() int { - f := func() int { // ERROR "func literal escapes to heap$" - return x - } - return f -} - -func foo23b(x int) *(func() int) { - f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$" - return &f -} - -func foo23c(x int) func() int { // ERROR "moved to heap: x$" - return func() int { // ERROR "func literal escapes to heap$" - x++ - return x - } -} - -func foo24(x int) int { - return func() int { // ERROR "foo24 func literal does not escape$" - return x - }() -} - -var x *int - -func fooleak(xx *int) int { // ERROR "leaking param: xx$" - x = xx - return *x -} - -func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$" - return *x + *xx -} - -func foo31(x int) int { // ERROR "moved to heap: x$" - return fooleak(&x) -} - -func foo32(x int) int { - return foonoleak(&x) -} - -type Foo struct { - xx *int - x int -} - -var F Foo -var pf *Foo - -func (f *Foo) fooleak() { // ERROR "leaking param: f$" - pf = f -} - -func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$" - F.x = f.x -} - -func (f *Foo) Leak() { // ERROR "leaking param: f$" - f.fooleak() -} - -func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$" - f.foonoleak() -} - -func foo41(x int) { // ERROR "moved to heap: x$" - F.xx = &x -} - -func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$" - f.xx = &x -} - -func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$" - f.xx = &x -} - -func foo44(yy *int) { // ERROR "leaking param: yy$" - F.xx = yy -} - -func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$" - F.x = f.x -} - -// See foo13 above for explanation of why f leaks. -func (f *Foo) foo46() { // ERROR "leaking param content: f$" - F.xx = f.xx -} - -func (f *Foo) foo47() { // ERROR "leaking param: f$" - f.xx = &f.x -} - -var ptrSlice []*int - -func foo50(i *int) { // ERROR "leaking param: i$" - ptrSlice[0] = i -} - -var ptrMap map[*int]*int - -func foo51(i *int) { // ERROR "leaking param: i$" - ptrMap[i] = i -} - -func indaddr1(x int) *int { // ERROR "moved to heap: x$" - return &x -} - -func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - return *&x -} - -func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$" - return *(**int)(unsafe.Pointer(&x)) -} - -// From package math: - -func Float32bits(f float32) uint32 { - return *(*uint32)(unsafe.Pointer(&f)) -} - -func Float32frombits(b uint32) float32 { - return *(*float32)(unsafe.Pointer(&b)) -} - -func Float64bits(f float64) uint64 { - return *(*uint64)(unsafe.Pointer(&f)) -} - -func Float64frombits(b uint64) float64 { - return *(*float64)(unsafe.Pointer(&b)) -} - -// contrast with -func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$" - return (*uint64)(unsafe.Pointer(&f)) -} - -func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$" - return (*uint64)(unsafe.Pointer(f)) -} - -func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$" - switch val := i.(type) { - case *int: - return val - case *int8: - v := int(*val) // ERROR "moved to heap: v$" - return &v - } - return nil -} - -func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" - switch j := i; *j + 110 { - case 12: - return j - case 42: - return nil - } - return nil - -} - -// assigning to an array element is like assigning to the array -func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" - var a [12]*int - a[0] = i - return a[1] -} - -func foo60a(i *int) *int { // ERROR "foo60a i does not escape$" - var a [12]*int - a[0] = i - return nil -} - -// assigning to a struct field is like assigning to the struct -func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" - type S struct { - a, b *int - } - var s S - s.a = i - return s.b -} - -func foo61a(i *int) *int { // ERROR "foo61a i does not escape$" - type S struct { - a, b *int - } - var s S - s.a = i - return nil -} - -// assigning to a struct field is like assigning to the struct but -// here this subtlety is lost, since s.a counts as an assignment to a -// track-losing dereference. -func foo62(i *int) *int { // ERROR "leaking param: i$" - type S struct { - a, b *int - } - s := new(S) // ERROR "foo62 new\(S\) does not escape$" - s.a = i - return nil // s.b -} - -type M interface { - M() -} - -func foo63(m M) { // ERROR "foo63 m does not escape$" -} - -func foo64(m M) { // ERROR "leaking param: m$" - m.M() -} - -func foo64b(m M) { // ERROR "leaking param: m$" - defer m.M() -} - -type MV int - -func (MV) M() {} - -func foo65() { - var mv MV - foo63(&mv) // ERROR "foo65 &mv does not escape$" -} - -func foo66() { - var mv MV // ERROR "moved to heap: mv$" - foo64(&mv) // ERROR "&mv escapes to heap$" -} - -func foo67() { - var mv MV - foo63(mv) // ERROR "foo67 mv does not escape$" -} - -func foo68() { - var mv MV - // escapes but it's an int so irrelevant - foo64(mv) // ERROR "mv escapes to heap$" -} - -func foo69(m M) { // ERROR "leaking param: m$" - foo64(m) -} - -func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$" - m = mv1 // ERROR "mv1 escapes to heap$" - foo64(m) -} - -func foo71(x *int) []*int { // ERROR "leaking param: x$" - var y []*int - y = append(y, x) - return y -} - -func foo71a(x int) []*int { // ERROR "moved to heap: x$" - var y []*int - y = append(y, &x) - return y -} - -func foo72() { - var x int - var y [1]*int - y[0] = &x -} - -func foo72aa() [10]*int { - var x int // ERROR "moved to heap: x$" - var y [10]*int - y[0] = &x - return y -} - -func foo72a() { - var y [10]*int - for i := 0; i < 10; i++ { - // escapes its scope - x := i // ERROR "moved to heap: x$" - y[i] = &x - } - return -} - -func foo72b() [10]*int { - var y [10]*int - for i := 0; i < 10; i++ { - x := i // ERROR "moved to heap: x$" - y[i] = &x - } - return y -} - -// issue 2145 -func foo73() { - s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$" - for _, v := range s { - vv := v - // actually just escapes its scope - defer func() { // ERROR "func literal escapes to heap$" - println(vv) - }() - } -} - -func foo731() { - s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$" - for _, v := range s { - vv := v // ERROR "moved to heap: vv$" - // actually just escapes its scope - defer func() { // ERROR "func literal escapes to heap$" - vv = 42 - println(vv) - }() - } -} - -func foo74() { - s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$" - for _, v := range s { - vv := v - // actually just escapes its scope - fn := func() { // ERROR "func literal escapes to heap$" - println(vv) - } - defer fn() - } -} - -func foo74a() { - s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$" - for _, v := range s { - vv := v // ERROR "moved to heap: vv$" - // actually just escapes its scope - fn := func() { // ERROR "func literal escapes to heap$" - vv += 1 - println(vv) - } - defer fn() - } -} - -// issue 3975 -func foo74b() { - var array [3]func() - s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$" - for i, v := range s { - vv := v - // actually just escapes its scope - array[i] = func() { // ERROR "func literal escapes to heap$" - println(vv) - } - } -} - -func foo74c() { - var array [3]func() - s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$" - for i, v := range s { - vv := v // ERROR "moved to heap: vv$" - // actually just escapes its scope - array[i] = func() { // ERROR "func literal escapes to heap$" - println(&vv) - } - } -} - -func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$" - return y -} - -func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$" - return &x[0] -} - -func foo75(z *int) { // ERROR "foo75 z does not escape$" - myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75 ... argument does not escape$" -} - -func foo75a(z *int) { // ERROR "foo75a z does not escape$" - myprint1(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75a ... argument does not escape$" -} - -func foo75esc(z *int) { // ERROR "leaking param: z$" - gxx = myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75esc ... argument does not escape$" -} - -func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$" - var ppi **interface{} // assignments to pointer dereferences lose track - *ppi = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" -} - -func foo75aesc1(z *int) { // ERROR "foo75aesc1 z does not escape$" - sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$" -} - -func foo76(z *int) { // ERROR "z does not escape" - myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z does not escape" -} - -func foo76a(z *int) { // ERROR "z does not escape" - myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z does not escape" -} - -func foo76b() { - myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76b ... argument does not escape$" -} - -func foo76c() { - myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76c ... argument does not escape$" -} - -func foo76d() { - defer myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76d ... argument does not escape$" -} - -func foo76e() { - defer myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76e ... argument does not escape$" -} - -func foo76f() { - for { - // TODO: This one really only escapes its scope, but we don't distinguish yet. - defer myprint(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" - } -} - -func foo76g() { - for { - defer myprint1(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" - } -} - -func foo77(z []interface{}) { // ERROR "foo77 z does not escape$" - myprint(nil, z...) // z does not escape -} - -func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$" - myprint1(nil, z...) -} - -func foo77b(z []interface{}) { // ERROR "leaking param: z$" - var ppi **interface{} - *ppi = myprint1(nil, z...) -} - -func foo77c(z []interface{}) { // ERROR "leaking param: z$" - sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$" -} - -func dotdotdot() { - i := 0 - myprint(nil, &i) // ERROR "&i does not escape" "dotdotdot ... argument does not escape$" - - j := 0 - myprint1(nil, &j) // ERROR "&j does not escape" "dotdotdot ... argument does not escape$" -} - -func foo78(z int) *int { // ERROR "moved to heap: z$" - return &z -} - -func foo78a(z int) *int { // ERROR "moved to heap: z$" - y := &z - x := &y - return *x // really return y -} - -func foo79() *int { - return new(int) // ERROR "new\(int\) escapes to heap$" -} - -func foo80() *int { - var z *int - for { - // Really just escapes its scope but we don't distinguish - z = new(int) // ERROR "new\(int\) escapes to heap$" - } - _ = z - return nil -} - -func foo81() *int { - for { - z := new(int) // ERROR "foo81 new\(int\) does not escape$" - _ = z - } - return nil -} - -func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$" - -func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$" - -func foo82() { - var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" - go noop(tee(&z)) - go noop(&x, &y) - for { - var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" - defer noop(tee(&u)) - defer noop(&v, &w) - } -} - -type Fooer interface { - Foo() -} - -type LimitedFooer struct { - Fooer - N int64 -} - -func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$" - return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal 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$" -} - -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$" -} - -func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" - return [2]*int{x, nil} -} - -// does not leak c -func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$" - for v := range c { - return v - } - return nil -} - -// does not leak m -func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1" - for k, v := range m { - if b { - return k - } - return v - } - return nil -} - -// does leak x -func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$" - m[x] = x -} - -// does not leak m but does leak content -func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" - return m[0] -} - -// does leak m -func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" - return m[0] -} - -// does not leak m -func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$" - return m[0] -} - -// does leak m -func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$" - return m[:] -} - -// does not leak m -func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" - for _, v := range m { - return v - } - return nil -} - -// does leak m -func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" - for _, v := range m { - return v - } - return nil -} - -// does not leak m -func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" - for i := range m { // ERROR "moved to heap: i$" - return &i - } - return nil -} - -// does leak x -func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$" - m[0] = x -} - -// does not leak x -func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$" - m[0] = x -} - -var y []*int - -// does not leak x but does leak content -func foo104(x []*int) { // ERROR "leaking param content: x" - copy(y, x) -} - -// does not leak x but does leak content -func foo105(x []*int) { // ERROR "leaking param content: x" - _ = append(y, x...) -} - -// does leak x -func foo106(x *int) { // ERROR "leaking param: x$" - _ = append(y, 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$" -} - -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$" -} - -func foo109(x *int) *int { // ERROR "leaking param: x$" - m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$" - for k, _ := range m { - return k - } - return nil -} - -func foo110(x *int) *int { // ERROR "leaking param: x$" - m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$" - return m[nil] -} - -func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" - m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$" - return m[0] -} - -func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - m := [1]*int{x} - return m[0] -} - -func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - m := Bar{ii: x} - return m.ii -} - -func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$" - return m.ii -} - -func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1)) -} - -func foo116(b bool) *int { - if b { - x := 1 // ERROR "moved to heap: x$" - return &x - } else { - y := 1 // ERROR "moved to heap: y$" - return &y - } - return nil -} - -func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$" - x := 1 // ERROR "moved to heap: x$" - unknown(&x) // ERROR "&x escapes to heap$" -} - -func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$" - x := 1 // ERROR "moved to heap: x$" - unknown(&x) -} - -func external(*int) - -func foo119(x *int) { // ERROR "leaking param: x$" - external(x) -} - -func foo120() { - // formerly exponential time analysis -L1: -L2: -L3: -L4: -L5: -L6: -L7: -L8: -L9: -L10: -L11: -L12: -L13: -L14: -L15: -L16: -L17: -L18: -L19: -L20: -L21: -L22: -L23: -L24: -L25: -L26: -L27: -L28: -L29: -L30: -L31: -L32: -L33: -L34: -L35: -L36: -L37: -L38: -L39: -L40: -L41: -L42: -L43: -L44: -L45: -L46: -L47: -L48: -L49: -L50: -L51: -L52: -L53: -L54: -L55: -L56: -L57: -L58: -L59: -L60: -L61: -L62: -L63: -L64: -L65: -L66: -L67: -L68: -L69: -L70: -L71: -L72: -L73: -L74: -L75: -L76: -L77: -L78: -L79: -L80: -L81: -L82: -L83: -L84: -L85: -L86: -L87: -L88: -L89: -L90: -L91: -L92: -L93: -L94: -L95: -L96: -L97: -L98: -L99: -L100: - // use the labels to silence compiler errors - goto L1 - goto L2 - goto L3 - goto L4 - goto L5 - goto L6 - goto L7 - goto L8 - goto L9 - goto L10 - goto L11 - goto L12 - goto L13 - goto L14 - goto L15 - goto L16 - goto L17 - goto L18 - goto L19 - goto L20 - goto L21 - goto L22 - goto L23 - goto L24 - goto L25 - goto L26 - goto L27 - goto L28 - goto L29 - goto L30 - goto L31 - goto L32 - goto L33 - goto L34 - goto L35 - goto L36 - goto L37 - goto L38 - goto L39 - goto L40 - goto L41 - goto L42 - goto L43 - goto L44 - goto L45 - goto L46 - goto L47 - goto L48 - goto L49 - goto L50 - goto L51 - goto L52 - goto L53 - goto L54 - goto L55 - goto L56 - goto L57 - goto L58 - goto L59 - goto L60 - goto L61 - goto L62 - goto L63 - goto L64 - goto L65 - goto L66 - goto L67 - goto L68 - goto L69 - goto L70 - goto L71 - goto L72 - goto L73 - goto L74 - goto L75 - goto L76 - goto L77 - goto L78 - goto L79 - goto L80 - goto L81 - goto L82 - goto L83 - goto L84 - goto L85 - goto L86 - goto L87 - goto L88 - goto L89 - goto L90 - goto L91 - goto L92 - goto L93 - goto L94 - goto L95 - goto L96 - goto L97 - goto L98 - goto L99 - goto L100 -} - -func foo121() { - for i := 0; i < 10; i++ { - defer myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$" - go myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$" - } -} - -// same as foo121 but check across import -func foo121b() { - for i := 0; i < 10; i++ { - defer fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$" - go fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$" - } -} - -// a harmless forward jump -func foo122() { - var i *int - - goto L1 -L1: - i = new(int) // ERROR "foo122 new\(int\) does not escape$" - _ = i -} - -// a backward jump, increases loopdepth -func foo123() { - var i *int - -L1: - i = new(int) // ERROR "new\(int\) escapes to heap$" - - goto L1 - _ = i -} - -func foo124(x **int) { // ERROR "foo124 x does not escape$" - var i int // ERROR "moved to heap: i$" - p := &i - func() { // ERROR "foo124 func literal does not escape$" - *x = p - }() -} - -func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$" - var i int // ERROR "moved to heap: i$" - p := &i - func() { // ERROR "foo125 func literal does not escape$" - ch <- p - }() -} - -func foo126() { - var px *int // loopdepth 0 - for { - // loopdepth 1 - var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo126 func literal does not escape$" - px = &i - }() - } - _ = px -} - -var px *int - -func foo127() { - var i int // ERROR "moved to heap: i$" - p := &i - q := p - px = q -} - -func foo128() { - var i int - p := &i - q := p - _ = q -} - -func foo129() { - var i int // ERROR "moved to heap: i$" - p := &i - func() { // ERROR "foo129 func literal does not escape$" - q := p - func() { // ERROR "foo129.func1 func literal does not escape$" - r := q - px = r - }() - }() -} - -func foo130() { - for { - var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo130 func literal does not escape$" - px = &i - }() - } -} - -func foo131() { - var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo131 func literal does not escape$" - px = &i - }() -} - -func foo132() { - var i int // ERROR "moved to heap: i$" - go func() { // ERROR "func literal escapes to heap$" - px = &i - }() -} - -func foo133() { - var i int // ERROR "moved to heap: i$" - defer func() { // ERROR "foo133 func literal does not escape$" - px = &i - }() -} - -func foo134() { - var i int - p := &i - func() { // ERROR "foo134 func literal does not escape$" - q := p - func() { // ERROR "foo134.func1 func literal does not escape$" - r := q - _ = r - }() - }() -} - -func foo135() { - var i int // ERROR "moved to heap: i$" - p := &i - go func() { // ERROR "func literal escapes to heap$" - q := p - func() { // ERROR "foo135.func1 func literal does not escape$" - r := q - _ = r - }() - }() -} - -func foo136() { - var i int // ERROR "moved to heap: i$" - p := &i - go func() { // ERROR "func literal escapes to heap$" - q := p - func() { // ERROR "foo136.func1 func literal does not escape$" - r := q - px = r - }() - }() -} - -func foo137() { - var i int // ERROR "moved to heap: i$" - p := &i - func() { // ERROR "foo137 func literal does not escape$" - q := p - go func() { // ERROR "func literal escapes to heap$" - r := q - _ = r - }() - }() -} - -func foo138() *byte { - type T struct { - x [1]byte - } - t := new(T) // ERROR "new\(T\) escapes to heap$" - return &t.x[0] -} - -func foo139() *byte { - type T struct { - x struct { - y byte - } - } - t := new(T) // ERROR "new\(T\) escapes to heap$" - return &t.x.y -} - -// issue 4751 -func foo140() interface{} { - type T struct { - X string - } - type U struct { - X string - T *T - } - t := &T{} // ERROR "&T literal escapes to heap$" - return U{ // ERROR "U literal escapes to heap$" - X: t.X, - T: t, - } -} - -//go:noescape - -func F1([]byte) - -func F2([]byte) - -//go:noescape - -func F3(x []byte) // ERROR "F3 x does not escape$" - -func F4(x []byte) - -func G() { - var buf1 [10]byte - F1(buf1[:]) - - var buf2 [10]byte // ERROR "moved to heap: buf2$" - F2(buf2[:]) - - var buf3 [10]byte - F3(buf3[:]) - - var buf4 [10]byte // ERROR "moved to heap: buf4$" - F4(buf4[:]) -} - -type Tm struct { - x int -} - -func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$" -} - -func foo141() { - var f func() - - t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" - f = t.M // ERROR "foo141 t.M does not escape$" - _ = f -} - -var gf func() - -func foo142() { - t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" - gf = t.M // ERROR "t.M escapes to heap$" -} - -// issue 3888. -func foo143() { - for i := 0; i < 1000; i++ { - func() { // ERROR "foo143 func literal does not escape$" - for i := 0; i < 1; i++ { - var t Tm - t.M() - } - }() - } -} - -// issue 5773 -// Check that annotations take effect regardless of whether they -// are before or after the use in the source code. - -//go:noescape - -func foo144a(*int) - -func foo144() { - var x int - foo144a(&x) - var y int - foo144b(&y) -} - -//go:noescape - -func foo144b(*int) - -// issue 7313: for loop init should not be treated as "in loop" - -type List struct { - Next *List -} - -func foo145(l List) { // ERROR "foo145 l does not escape$" - var p *List - for p = &l; p.Next != nil; p = p.Next { - } -} - -func foo146(l List) { // ERROR "foo146 l does not escape$" - var p *List - p = &l - for ; p.Next != nil; p = p.Next { - } -} - -func foo147(l List) { // ERROR "foo147 l does not escape$" - var p *List - p = &l - for p.Next != nil { - p = p.Next - } -} - -func foo148(l List) { // ERROR "foo148 l does not escape$" - for p := &l; p.Next != nil; p = p.Next { - } -} - -// related: address of variable should have depth of variable, not of loop - -func foo149(l List) { // ERROR "foo149 l does not escape$" - var p *List - for { - for p = &l; p.Next != nil; p = p.Next { - } - } -} - -// issue 7934: missed ... if element type had no pointers - -var save150 []byte - -func foo150(x ...byte) { // ERROR "leaking param: x$" - save150 = x -} - -func bar150() { - foo150(1, 2, 3) // ERROR "... argument escapes to heap$" -} - -// issue 7931: bad handling of slice of array - -var save151 *int - -func foo151(x *int) { // ERROR "leaking param: x$" - save151 = x -} - -func bar151() { - var a [64]int // ERROR "moved to heap: a$" - a[4] = 101 - foo151(&(&a)[4:8][0]) -} - -func bar151b() { - var a [10]int // ERROR "moved to heap: a$" - b := a[:] - foo151(&b[4:8][0]) -} - -func bar151c() { - var a [64]int // ERROR "moved to heap: a$" - a[4] = 101 - foo151(&(&a)[4:8:8][0]) -} - -func bar151d() { - var a [10]int // ERROR "moved to heap: a$" - b := a[:] - foo151(&b[4:8:8][0]) -} - -// issue 8120 - -type U struct { - s *string -} - -func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$" - return u.s -} - -type V struct { - s *string -} - -// BAD -- level of leak ought to be 0 -func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1" - return &V{u.String()} // ERROR "&V literal escapes to heap$" -} - -func foo152() { - a := "a" // ERROR "moved to heap: a$" - u := U{&a} - v := NewV(u) - println(v) -} - -// issue 8176 - &x in type switch body not marked as escaping - -func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$" - switch x := v.(type) { - case int: // ERROR "moved to heap: x$" - return &x - } - panic(0) -} - -// issue 8185 - &result escaping into result - -func f() (x int, y *int) { // ERROR "moved to heap: x$" - y = &x - return -} - -func g() (x interface{}) { // ERROR "moved to heap: x$" - x = &x // ERROR "&x escapes to heap$" - return -} - -var sink interface{} - -type Lit struct { - p *int -} - -func ptrlitNoescape() { - // Both literal and element do not escape. - i := 0 - x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" - _ = x -} - -func ptrlitNoEscape2() { - // Literal does not escape, but element does. - i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "ptrlitNoEscape2 &Lit literal does not escape$" - sink = *x // ERROR "\*x escapes to heap$" -} - -func ptrlitEscape() { - // Both literal and element escape. - i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" - sink = x // ERROR "x escapes to heap$" -} - -// self-assignments - -type Buffer struct { - arr [64]byte - arrPtr *[64]byte - buf1 []byte - buf2 []byte - str1 string - str2 string -} - -func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$" - b.buf1 = b.buf1[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2\]$" - b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2:3\]$" - b.buf1 = b.buf2[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2\]$" - b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2:3\]$" -} - -func (b *Buffer) bar() { // ERROR "leaking param: b$" - b.buf1 = b.arr[1:2] -} - -func (b *Buffer) arrayPtr() { // ERROR "\(\*Buffer\).arrayPtr b does not escape" - b.buf1 = b.arrPtr[1:2] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2\]$" - b.buf1 = b.arrPtr[1:2:3] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2:3\]$" -} - -func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$" - b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str1\[1:2\]$" - b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str2\[1:2\]$" -} - -func (b *Buffer) bat() { // ERROR "leaking param content: b$" - o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$" - o.buf1 = b.buf1[1:2] - sink = o // ERROR "o escapes to heap$" -} - -func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$" - *sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment in \*sp = \(\*sp\)\[1:2\]$" - *bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment in \*bp = \(\*bp\)\[1:2\]$" -} - -type StructWithString struct { - p *int - s string -} - -// This is escape analysis false negative. -// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows -// to just x, and thus &i looks escaping. -func fieldFlowTracking() { - var x StructWithString - i := 0 // ERROR "moved to heap: i$" - x.p = &i - sink = x.s // ERROR "x.s escapes to heap$" -} - -// String operations. - -func slicebytetostring0() { - b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "slicebytetostring0 string\(b\) does not escape$" - _ = s -} - -func slicebytetostring1() { - b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "slicebytetostring1 string\(b\) does not escape$" - s1 := s[0:1] - _ = s1 -} - -func slicebytetostring2() { - b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "string\(b\) escapes to heap$" - s1 := s[0:1] // ERROR "moved to heap: s1$" - sink = &s1 // ERROR "&s1 escapes to heap$" -} - -func slicebytetostring3() { - b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "string\(b\) escapes to heap$" - s1 := s[0:1] - sink = s1 // ERROR "s1 escapes to heap$" -} - -func addstr0() { - s0 := "a" - s1 := "b" - s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$" - _ = s -} - -func addstr1() { - s0 := "a" - s1 := "b" - s := "c" - s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$" - _ = s -} - -func addstr2() { - b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$" - s0 := "a" - s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$" - _ = s -} - -func addstr3() { - s0 := "a" - s1 := "b" - s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$" - s2 := s[0:1] - sink = s2 // ERROR "s2 escapes to heap$" -} - -func intstring0() bool { - // string does not escape - x := '0' - s := string(x) // ERROR "intstring0 string\(x\) does not escape$" - return s == "0" -} - -func intstring1() string { - // string does not escape, but the buffer does - x := '0' - s := string(x) // ERROR "string\(x\) escapes to heap$" - return s -} - -func intstring2() { - // string escapes to heap - x := '0' - s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$" - sink = &s // ERROR "&s escapes to heap$" -} - -func stringtoslicebyte0() { - s := "foo" - x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$" - _ = x -} - -func stringtoslicebyte1() []byte { - s := "foo" - return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" -} - -func stringtoslicebyte2() { - s := "foo" - sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" -} - -func stringtoslicerune0() { - s := "foo" - x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$" - _ = x -} - -func stringtoslicerune1() []rune { - s := "foo" - return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" -} - -func stringtoslicerune2() { - s := "foo" - sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" -} - -func slicerunetostring0() { - r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$" - s := string(r) // ERROR "slicerunetostring0 string\(r\) does not escape$" - _ = s -} - -func slicerunetostring1() string { - r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$" - return string(r) // ERROR "string\(r\) escapes to heap$" -} - -func slicerunetostring2() { - r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$" - sink = string(r) // ERROR "string\(r\) escapes to heap$" -} - -func makemap0() { - m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$" - m[0] = 0 - m[1]++ - delete(m, 1) - sink = m[0] // ERROR "m\[0\] escapes to heap$" -} - -func makemap1() map[int]int { - return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" -} - -func makemap2() { - m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" - sink = m // ERROR "m escapes to heap$" -} - -func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$" - return m["foo"] // ERROR "nonescapingEface .foo. does not escape$" -} - -func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$" - return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$" -} - -func issue10353() { - x := new(int) // ERROR "new\(int\) escapes to heap$" - issue10353a(x)() -} - -func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$" - return func() { // ERROR "func literal escapes to heap$" - println(*x) - } -} - -func issue10353b() { - var f func() - for { - x := new(int) // ERROR "new\(int\) escapes to heap$" - f = func() { // ERROR "func literal escapes to heap$" - println(*x) - } - } - _ = f -} - -func issue11387(x int) func() int { - f := func() int { return x } // ERROR "func literal escapes to heap" - slice1 := []func() int{f} // ERROR "\[\].* does not escape" - slice2 := make([]func() int, 1) // ERROR "make\(.*\) does not escape" - copy(slice2, slice1) - return slice2[0] -} - -func issue12397(x, y int) { // ERROR "moved to heap: y$" - // x does not escape below, because all relevant code is dead. - if false { - gxx = &x - } else { - gxx = &y - } - - if true { - gxx = &y - } else { - gxx = &x - } -} diff --git a/test/oldescape2n.go b/test/oldescape2n.go deleted file mode 100644 index fb2a9566..00000000 --- a/test/oldescape2n.go +++ /dev/null @@ -1,1847 +0,0 @@ -// errorcheck -0 -N -m -l -newescape=false - -// Copyright 2010 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. - -// Test, using compiler diagnostic flags, that the escape analysis is working. -// Compiles but does not run. Inlining is disabled. -// Registerization is disabled too (-N), which should -// have no effect on escape analysis. - -package foo - -import ( - "fmt" - "unsafe" -) - -var gxx *int - -func foo1(x int) { // ERROR "moved to heap: x$" - gxx = &x -} - -func foo2(yy *int) { // ERROR "leaking param: yy$" - gxx = yy -} - -func foo3(x int) *int { // ERROR "moved to heap: x$" - return &x -} - -type T *T - -func foo3b(t T) { // ERROR "leaking param: t$" - *t = t -} - -// xx isn't going anywhere, so use of yy is ok -func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$" - xx = yy -} - -// xx isn't going anywhere, so taking address of yy is ok -func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$" - xx = &yy -} - -func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$" - *xx = yy -} - -func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$" - **xx = *yy -} - -func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$" - xx = yy - return *xx -} - -func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$" - xx = yy - return xx -} - -func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$" - *xx = *yy -} - -func foo11() int { - x, y := 0, 42 - xx := &x - yy := &y - *xx = *yy - return x -} - -var xxx **int - -func foo12(yyy **int) { // ERROR "leaking param: yyy$" - xxx = yyy -} - -// Must treat yyy as leaking because *yyy leaks, and the escape analysis -// summaries in exported metadata do not distinguish these two cases. -func foo13(yyy **int) { // ERROR "leaking param content: yyy$" - *xxx = *yyy -} - -func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$" - **xxx = **yyy -} - -func foo15(yy *int) { // ERROR "moved to heap: yy$" - xxx = &yy -} - -func foo16(yy *int) { // ERROR "leaking param: yy$" - *xxx = yy -} - -func foo17(yy *int) { // ERROR "foo17 yy does not escape$" - **xxx = *yy -} - -func foo18(y int) { // ERROR "moved to heap: y$" - *xxx = &y -} - -func foo19(y int) { - **xxx = y -} - -type Bar struct { - i int - ii *int -} - -func NewBar() *Bar { - return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$" -} - -func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$" - return &Bar{42, x} // ERROR "&Bar literal escapes to heap$" -} - -func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$" - return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$" -} - -func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$" - return *(b.ii) -} - -func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$" - return &b.i -} - -func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$" - return b.ii -} - -func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$" - return b.ii -} - -func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$" - v := 0 // ERROR "moved to heap: v$" - b.ii = &v - return b.ii -} - -func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$" - v := 0 // ERROR "moved to heap: v$" - b.ii = &v - return b.ii -} - -func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$" - v := 0 - b.ii = &v - return b.i -} - -func goLeak(b *Bar) { // ERROR "leaking param: b$" - go b.NoLeak() -} - -type Bar2 struct { - i [12]int - ii []int -} - -func NewBar2() *Bar2 { - return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$" -} - -func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$" - return b.i[0] -} - -func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$" - return b.i[:] -} - -func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$" - return b.ii[0:1] -} - -func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$" - return b.i -} - -func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$" - b.ii = b.i[0:4] -} - -func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$" - var buf []int - buf = b.i[0:] - b.ii = buf -} - -func foo21() func() int { - x := 42 - return func() int { // ERROR "func literal escapes to heap$" - return x - } -} - -func foo21a() func() int { - x := 42 // ERROR "moved to heap: x$" - return func() int { // ERROR "func literal escapes to heap$" - x++ - return x - } -} - -func foo22() int { - x := 42 - return func() int { // ERROR "foo22 func literal does not escape$" - return x - }() -} - -func foo23(x int) func() int { - return func() int { // ERROR "func literal escapes to heap$" - return x - } -} - -func foo23a(x int) func() int { - f := func() int { // ERROR "func literal escapes to heap$" - return x - } - return f -} - -func foo23b(x int) *(func() int) { - f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$" - return &f -} - -func foo23c(x int) func() int { // ERROR "moved to heap: x$" - return func() int { // ERROR "func literal escapes to heap$" - x++ - return x - } -} - -func foo24(x int) int { - return func() int { // ERROR "foo24 func literal does not escape$" - return x - }() -} - -var x *int - -func fooleak(xx *int) int { // ERROR "leaking param: xx$" - x = xx - return *x -} - -func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$" - return *x + *xx -} - -func foo31(x int) int { // ERROR "moved to heap: x$" - return fooleak(&x) -} - -func foo32(x int) int { - return foonoleak(&x) -} - -type Foo struct { - xx *int - x int -} - -var F Foo -var pf *Foo - -func (f *Foo) fooleak() { // ERROR "leaking param: f$" - pf = f -} - -func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$" - F.x = f.x -} - -func (f *Foo) Leak() { // ERROR "leaking param: f$" - f.fooleak() -} - -func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$" - f.foonoleak() -} - -func foo41(x int) { // ERROR "moved to heap: x$" - F.xx = &x -} - -func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$" - f.xx = &x -} - -func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$" - f.xx = &x -} - -func foo44(yy *int) { // ERROR "leaking param: yy$" - F.xx = yy -} - -func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$" - F.x = f.x -} - -// See foo13 above for explanation of why f leaks. -func (f *Foo) foo46() { // ERROR "leaking param content: f$" - F.xx = f.xx -} - -func (f *Foo) foo47() { // ERROR "leaking param: f$" - f.xx = &f.x -} - -var ptrSlice []*int - -func foo50(i *int) { // ERROR "leaking param: i$" - ptrSlice[0] = i -} - -var ptrMap map[*int]*int - -func foo51(i *int) { // ERROR "leaking param: i$" - ptrMap[i] = i -} - -func indaddr1(x int) *int { // ERROR "moved to heap: x$" - return &x -} - -func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - return *&x -} - -func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$" - return *(**int)(unsafe.Pointer(&x)) -} - -// From package math: - -func Float32bits(f float32) uint32 { - return *(*uint32)(unsafe.Pointer(&f)) -} - -func Float32frombits(b uint32) float32 { - return *(*float32)(unsafe.Pointer(&b)) -} - -func Float64bits(f float64) uint64 { - return *(*uint64)(unsafe.Pointer(&f)) -} - -func Float64frombits(b uint64) float64 { - return *(*float64)(unsafe.Pointer(&b)) -} - -// contrast with -func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$" - return (*uint64)(unsafe.Pointer(&f)) -} - -func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$" - return (*uint64)(unsafe.Pointer(f)) -} - -func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$" - switch val := i.(type) { - case *int: - return val - case *int8: - v := int(*val) // ERROR "moved to heap: v$" - return &v - } - return nil -} - -func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" - switch j := i; *j + 110 { - case 12: - return j - case 42: - return nil - } - return nil - -} - -// assigning to an array element is like assigning to the array -func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" - var a [12]*int - a[0] = i - return a[1] -} - -func foo60a(i *int) *int { // ERROR "foo60a i does not escape$" - var a [12]*int - a[0] = i - return nil -} - -// assigning to a struct field is like assigning to the struct -func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$" - type S struct { - a, b *int - } - var s S - s.a = i - return s.b -} - -func foo61a(i *int) *int { // ERROR "foo61a i does not escape$" - type S struct { - a, b *int - } - var s S - s.a = i - return nil -} - -// assigning to a struct field is like assigning to the struct but -// here this subtlety is lost, since s.a counts as an assignment to a -// track-losing dereference. -func foo62(i *int) *int { // ERROR "leaking param: i$" - type S struct { - a, b *int - } - s := new(S) // ERROR "foo62 new\(S\) does not escape$" - s.a = i - return nil // s.b -} - -type M interface { - M() -} - -func foo63(m M) { // ERROR "foo63 m does not escape$" -} - -func foo64(m M) { // ERROR "leaking param: m$" - m.M() -} - -func foo64b(m M) { // ERROR "leaking param: m$" - defer m.M() -} - -type MV int - -func (MV) M() {} - -func foo65() { - var mv MV - foo63(&mv) // ERROR "foo65 &mv does not escape$" -} - -func foo66() { - var mv MV // ERROR "moved to heap: mv$" - foo64(&mv) // ERROR "&mv escapes to heap$" -} - -func foo67() { - var mv MV - foo63(mv) // ERROR "foo67 mv does not escape$" -} - -func foo68() { - var mv MV - // escapes but it's an int so irrelevant - foo64(mv) // ERROR "mv escapes to heap$" -} - -func foo69(m M) { // ERROR "leaking param: m$" - foo64(m) -} - -func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$" - m = mv1 // ERROR "mv1 escapes to heap$" - foo64(m) -} - -func foo71(x *int) []*int { // ERROR "leaking param: x$" - var y []*int - y = append(y, x) - return y -} - -func foo71a(x int) []*int { // ERROR "moved to heap: x$" - var y []*int - y = append(y, &x) - return y -} - -func foo72() { - var x int - var y [1]*int - y[0] = &x -} - -func foo72aa() [10]*int { - var x int // ERROR "moved to heap: x$" - var y [10]*int - y[0] = &x - return y -} - -func foo72a() { - var y [10]*int - for i := 0; i < 10; i++ { - // escapes its scope - x := i // ERROR "moved to heap: x$" - y[i] = &x - } - return -} - -func foo72b() [10]*int { - var y [10]*int - for i := 0; i < 10; i++ { - x := i // ERROR "moved to heap: x$" - y[i] = &x - } - return y -} - -// issue 2145 -func foo73() { - s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$" - for _, v := range s { - vv := v - // actually just escapes its scope - defer func() { // ERROR "func literal escapes to heap$" - println(vv) - }() - } -} - -func foo731() { - s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$" - for _, v := range s { - vv := v // ERROR "moved to heap: vv$" - // actually just escapes its scope - defer func() { // ERROR "func literal escapes to heap$" - vv = 42 - println(vv) - }() - } -} - -func foo74() { - s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$" - for _, v := range s { - vv := v - // actually just escapes its scope - fn := func() { // ERROR "func literal escapes to heap$" - println(vv) - } - defer fn() - } -} - -func foo74a() { - s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$" - for _, v := range s { - vv := v // ERROR "moved to heap: vv$" - // actually just escapes its scope - fn := func() { // ERROR "func literal escapes to heap$" - vv += 1 - println(vv) - } - defer fn() - } -} - -// issue 3975 -func foo74b() { - var array [3]func() - s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$" - for i, v := range s { - vv := v - // actually just escapes its scope - array[i] = func() { // ERROR "func literal escapes to heap$" - println(vv) - } - } -} - -func foo74c() { - var array [3]func() - s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$" - for i, v := range s { - vv := v // ERROR "moved to heap: vv$" - // actually just escapes its scope - array[i] = func() { // ERROR "func literal escapes to heap$" - println(&vv) - } - } -} - -func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$" - return y -} - -func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$" - return &x[0] -} - -func foo75(z *int) { // ERROR "foo75 z does not escape$" - myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75 ... argument does not escape$" -} - -func foo75a(z *int) { // ERROR "foo75a z does not escape$" - myprint1(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75a ... argument does not escape$" -} - -func foo75esc(z *int) { // ERROR "leaking param: z$" - gxx = myprint(z, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo75esc ... argument does not escape$" -} - -func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$" - var ppi **interface{} // assignments to pointer dereferences lose track - *ppi = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" -} - -func foo75aesc1(z *int) { // ERROR "foo75aesc1 z does not escape$" - sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$" -} - -func foo76(z *int) { // ERROR "z does not escape" - myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z does not escape" -} - -func foo76a(z *int) { // ERROR "z does not escape" - myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z does not escape" -} - -func foo76b() { - myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76b ... argument does not escape$" -} - -func foo76c() { - myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76c ... argument does not escape$" -} - -func foo76d() { - defer myprint(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76d ... argument does not escape$" -} - -func foo76e() { - defer myprint1(nil, 1, 2, 3) // ERROR "1 does not escape" "2 does not escape" "3 does not escape" "foo76e ... argument does not escape$" -} - -func foo76f() { - for { - // TODO: This one really only escapes its scope, but we don't distinguish yet. - defer myprint(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" - } -} - -func foo76g() { - for { - defer myprint1(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" - } -} - -func foo77(z []interface{}) { // ERROR "foo77 z does not escape$" - myprint(nil, z...) // z does not escape -} - -func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$" - myprint1(nil, z...) -} - -func foo77b(z []interface{}) { // ERROR "leaking param: z$" - var ppi **interface{} - *ppi = myprint1(nil, z...) -} - -func foo77c(z []interface{}) { // ERROR "leaking param: z$" - sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$" -} - -func dotdotdot() { - i := 0 - myprint(nil, &i) // ERROR "&i does not escape" "dotdotdot ... argument does not escape$" - - j := 0 - myprint1(nil, &j) // ERROR "&j does not escape" "dotdotdot ... argument does not escape$" -} - -func foo78(z int) *int { // ERROR "moved to heap: z$" - return &z -} - -func foo78a(z int) *int { // ERROR "moved to heap: z$" - y := &z - x := &y - return *x // really return y -} - -func foo79() *int { - return new(int) // ERROR "new\(int\) escapes to heap$" -} - -func foo80() *int { - var z *int - for { - // Really just escapes its scope but we don't distinguish - z = new(int) // ERROR "new\(int\) escapes to heap$" - } - _ = z - return nil -} - -func foo81() *int { - for { - z := new(int) // ERROR "foo81 new\(int\) does not escape$" - _ = z - } - return nil -} - -func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$" - -func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$" - -func foo82() { - var x, y, z int // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$" - go noop(tee(&z)) - go noop(&x, &y) - for { - var u, v, w int // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$" - defer noop(tee(&u)) - defer noop(&v, &w) - } -} - -type Fooer interface { - Foo() -} - -type LimitedFooer struct { - Fooer - N int64 -} - -func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$" - return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal 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$" -} - -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$" -} - -func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$" - return [2]*int{x, nil} -} - -// does not leak c -func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$" - for v := range c { - return v - } - return nil -} - -// does not leak m -func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1" - for k, v := range m { - if b { - return k - } - return v - } - return nil -} - -// does leak x -func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$" - m[x] = x -} - -// does not leak m but does leak content -func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" - return m[0] -} - -// does leak m -func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" - return m[0] -} - -// does not leak m -func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$" - return m[0] -} - -// does leak m -func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$" - return m[:] -} - -// does not leak m -func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1" - for _, v := range m { - return v - } - return nil -} - -// does leak m -func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$" - for _, v := range m { - return v - } - return nil -} - -// does not leak m -func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$" - for i := range m { // ERROR "moved to heap: i$" - return &i - } - return nil -} - -// does leak x -func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$" - m[0] = x -} - -// does not leak x -func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$" - m[0] = x -} - -var y []*int - -// does not leak x but does leak content -func foo104(x []*int) { // ERROR "leaking param content: x" - copy(y, x) -} - -// does not leak x but does leak content -func foo105(x []*int) { // ERROR "leaking param content: x" - _ = append(y, x...) -} - -// does leak x -func foo106(x *int) { // ERROR "leaking param: x$" - _ = append(y, 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$" -} - -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$" -} - -func foo109(x *int) *int { // ERROR "leaking param: x$" - m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$" - for k, _ := range m { - return k - } - return nil -} - -func foo110(x *int) *int { // ERROR "leaking param: x$" - m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$" - return m[nil] -} - -func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0" - m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$" - return m[0] -} - -func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - m := [1]*int{x} - return m[0] -} - -func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - m := Bar{ii: x} - return m.ii -} - -func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$" - return m.ii -} - -func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$" - return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1)) -} - -func foo116(b bool) *int { - if b { - x := 1 // ERROR "moved to heap: x$" - return &x - } else { - y := 1 // ERROR "moved to heap: y$" - return &y - } - return nil -} - -func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$" - x := 1 // ERROR "moved to heap: x$" - unknown(&x) // ERROR "&x escapes to heap$" -} - -func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$" - x := 1 // ERROR "moved to heap: x$" - unknown(&x) -} - -func external(*int) - -func foo119(x *int) { // ERROR "leaking param: x$" - external(x) -} - -func foo120() { - // formerly exponential time analysis -L1: -L2: -L3: -L4: -L5: -L6: -L7: -L8: -L9: -L10: -L11: -L12: -L13: -L14: -L15: -L16: -L17: -L18: -L19: -L20: -L21: -L22: -L23: -L24: -L25: -L26: -L27: -L28: -L29: -L30: -L31: -L32: -L33: -L34: -L35: -L36: -L37: -L38: -L39: -L40: -L41: -L42: -L43: -L44: -L45: -L46: -L47: -L48: -L49: -L50: -L51: -L52: -L53: -L54: -L55: -L56: -L57: -L58: -L59: -L60: -L61: -L62: -L63: -L64: -L65: -L66: -L67: -L68: -L69: -L70: -L71: -L72: -L73: -L74: -L75: -L76: -L77: -L78: -L79: -L80: -L81: -L82: -L83: -L84: -L85: -L86: -L87: -L88: -L89: -L90: -L91: -L92: -L93: -L94: -L95: -L96: -L97: -L98: -L99: -L100: - // use the labels to silence compiler errors - goto L1 - goto L2 - goto L3 - goto L4 - goto L5 - goto L6 - goto L7 - goto L8 - goto L9 - goto L10 - goto L11 - goto L12 - goto L13 - goto L14 - goto L15 - goto L16 - goto L17 - goto L18 - goto L19 - goto L20 - goto L21 - goto L22 - goto L23 - goto L24 - goto L25 - goto L26 - goto L27 - goto L28 - goto L29 - goto L30 - goto L31 - goto L32 - goto L33 - goto L34 - goto L35 - goto L36 - goto L37 - goto L38 - goto L39 - goto L40 - goto L41 - goto L42 - goto L43 - goto L44 - goto L45 - goto L46 - goto L47 - goto L48 - goto L49 - goto L50 - goto L51 - goto L52 - goto L53 - goto L54 - goto L55 - goto L56 - goto L57 - goto L58 - goto L59 - goto L60 - goto L61 - goto L62 - goto L63 - goto L64 - goto L65 - goto L66 - goto L67 - goto L68 - goto L69 - goto L70 - goto L71 - goto L72 - goto L73 - goto L74 - goto L75 - goto L76 - goto L77 - goto L78 - goto L79 - goto L80 - goto L81 - goto L82 - goto L83 - goto L84 - goto L85 - goto L86 - goto L87 - goto L88 - goto L89 - goto L90 - goto L91 - goto L92 - goto L93 - goto L94 - goto L95 - goto L96 - goto L97 - goto L98 - goto L99 - goto L100 -} - -func foo121() { - for i := 0; i < 10; i++ { - defer myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$" - go myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$" - } -} - -// same as foo121 but check across import -func foo121b() { - for i := 0; i < 10; i++ { - defer fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$" - go fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$" - } -} - -// a harmless forward jump -func foo122() { - var i *int - - goto L1 -L1: - i = new(int) // ERROR "foo122 new\(int\) does not escape$" - _ = i -} - -// a backward jump, increases loopdepth -func foo123() { - var i *int - -L1: - i = new(int) // ERROR "new\(int\) escapes to heap$" - - goto L1 - _ = i -} - -func foo124(x **int) { // ERROR "foo124 x does not escape$" - var i int // ERROR "moved to heap: i$" - p := &i - func() { // ERROR "foo124 func literal does not escape$" - *x = p - }() -} - -func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$" - var i int // ERROR "moved to heap: i$" - p := &i - func() { // ERROR "foo125 func literal does not escape$" - ch <- p - }() -} - -func foo126() { - var px *int // loopdepth 0 - for { - // loopdepth 1 - var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo126 func literal does not escape$" - px = &i - }() - } - _ = px -} - -var px *int - -func foo127() { - var i int // ERROR "moved to heap: i$" - p := &i - q := p - px = q -} - -func foo128() { - var i int - p := &i - q := p - _ = q -} - -func foo129() { - var i int // ERROR "moved to heap: i$" - p := &i - func() { // ERROR "foo129 func literal does not escape$" - q := p - func() { // ERROR "foo129.func1 func literal does not escape$" - r := q - px = r - }() - }() -} - -func foo130() { - for { - var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo130 func literal does not escape$" - px = &i - }() - } -} - -func foo131() { - var i int // ERROR "moved to heap: i$" - func() { // ERROR "foo131 func literal does not escape$" - px = &i - }() -} - -func foo132() { - var i int // ERROR "moved to heap: i$" - go func() { // ERROR "func literal escapes to heap$" - px = &i - }() -} - -func foo133() { - var i int // ERROR "moved to heap: i$" - defer func() { // ERROR "foo133 func literal does not escape$" - px = &i - }() -} - -func foo134() { - var i int - p := &i - func() { // ERROR "foo134 func literal does not escape$" - q := p - func() { // ERROR "foo134.func1 func literal does not escape$" - r := q - _ = r - }() - }() -} - -func foo135() { - var i int // ERROR "moved to heap: i$" - p := &i - go func() { // ERROR "func literal escapes to heap$" - q := p - func() { // ERROR "foo135.func1 func literal does not escape$" - r := q - _ = r - }() - }() -} - -func foo136() { - var i int // ERROR "moved to heap: i$" - p := &i - go func() { // ERROR "func literal escapes to heap$" - q := p - func() { // ERROR "foo136.func1 func literal does not escape$" - r := q - px = r - }() - }() -} - -func foo137() { - var i int // ERROR "moved to heap: i$" - p := &i - func() { // ERROR "foo137 func literal does not escape$" - q := p - go func() { // ERROR "func literal escapes to heap$" - r := q - _ = r - }() - }() -} - -func foo138() *byte { - type T struct { - x [1]byte - } - t := new(T) // ERROR "new\(T\) escapes to heap$" - return &t.x[0] -} - -func foo139() *byte { - type T struct { - x struct { - y byte - } - } - t := new(T) // ERROR "new\(T\) escapes to heap$" - return &t.x.y -} - -// issue 4751 -func foo140() interface{} { - type T struct { - X string - } - type U struct { - X string - T *T - } - t := &T{} // ERROR "&T literal escapes to heap$" - return U{ // ERROR "U literal escapes to heap$" - X: t.X, - T: t, - } -} - -//go:noescape - -func F1([]byte) - -func F2([]byte) - -//go:noescape - -func F3(x []byte) // ERROR "F3 x does not escape$" - -func F4(x []byte) - -func G() { - var buf1 [10]byte - F1(buf1[:]) - - var buf2 [10]byte // ERROR "moved to heap: buf2$" - F2(buf2[:]) - - var buf3 [10]byte - F3(buf3[:]) - - var buf4 [10]byte // ERROR "moved to heap: buf4$" - F4(buf4[:]) -} - -type Tm struct { - x int -} - -func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$" -} - -func foo141() { - var f func() - - t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" - f = t.M // ERROR "foo141 t.M does not escape$" - _ = f -} - -var gf func() - -func foo142() { - t := new(Tm) // ERROR "new\(Tm\) escapes to heap$" - gf = t.M // ERROR "t.M escapes to heap$" -} - -// issue 3888. -func foo143() { - for i := 0; i < 1000; i++ { - func() { // ERROR "foo143 func literal does not escape$" - for i := 0; i < 1; i++ { - var t Tm - t.M() - } - }() - } -} - -// issue 5773 -// Check that annotations take effect regardless of whether they -// are before or after the use in the source code. - -//go:noescape - -func foo144a(*int) - -func foo144() { - var x int - foo144a(&x) - var y int - foo144b(&y) -} - -//go:noescape - -func foo144b(*int) - -// issue 7313: for loop init should not be treated as "in loop" - -type List struct { - Next *List -} - -func foo145(l List) { // ERROR "foo145 l does not escape$" - var p *List - for p = &l; p.Next != nil; p = p.Next { - } -} - -func foo146(l List) { // ERROR "foo146 l does not escape$" - var p *List - p = &l - for ; p.Next != nil; p = p.Next { - } -} - -func foo147(l List) { // ERROR "foo147 l does not escape$" - var p *List - p = &l - for p.Next != nil { - p = p.Next - } -} - -func foo148(l List) { // ERROR "foo148 l does not escape$" - for p := &l; p.Next != nil; p = p.Next { - } -} - -// related: address of variable should have depth of variable, not of loop - -func foo149(l List) { // ERROR "foo149 l does not escape$" - var p *List - for { - for p = &l; p.Next != nil; p = p.Next { - } - } -} - -// issue 7934: missed ... if element type had no pointers - -var save150 []byte - -func foo150(x ...byte) { // ERROR "leaking param: x$" - save150 = x -} - -func bar150() { - foo150(1, 2, 3) // ERROR "... argument escapes to heap$" -} - -// issue 7931: bad handling of slice of array - -var save151 *int - -func foo151(x *int) { // ERROR "leaking param: x$" - save151 = x -} - -func bar151() { - var a [64]int // ERROR "moved to heap: a$" - a[4] = 101 - foo151(&(&a)[4:8][0]) -} - -func bar151b() { - var a [10]int // ERROR "moved to heap: a$" - b := a[:] - foo151(&b[4:8][0]) -} - -func bar151c() { - var a [64]int // ERROR "moved to heap: a$" - a[4] = 101 - foo151(&(&a)[4:8:8][0]) -} - -func bar151d() { - var a [10]int // ERROR "moved to heap: a$" - b := a[:] - foo151(&b[4:8:8][0]) -} - -// issue 8120 - -type U struct { - s *string -} - -func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$" - return u.s -} - -type V struct { - s *string -} - -// BAD -- level of leak ought to be 0 -func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1" - return &V{u.String()} // ERROR "&V literal escapes to heap$" -} - -func foo152() { - a := "a" // ERROR "moved to heap: a$" - u := U{&a} - v := NewV(u) - println(v) -} - -// issue 8176 - &x in type switch body not marked as escaping - -func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$" - switch x := v.(type) { - case int: // ERROR "moved to heap: x$" - return &x - } - panic(0) -} - -// issue 8185 - &result escaping into result - -func f() (x int, y *int) { // ERROR "moved to heap: x$" - y = &x - return -} - -func g() (x interface{}) { // ERROR "moved to heap: x$" - x = &x // ERROR "&x escapes to heap$" - return -} - -var sink interface{} - -type Lit struct { - p *int -} - -func ptrlitNoescape() { - // Both literal and element do not escape. - i := 0 - x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" - _ = x -} - -func ptrlitNoEscape2() { - // Literal does not escape, but element does. - i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "ptrlitNoEscape2 &Lit literal does not escape$" - sink = *x // ERROR "\*x escapes to heap$" -} - -func ptrlitEscape() { - // Both literal and element escape. - i := 0 // ERROR "moved to heap: i$" - x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" - sink = x // ERROR "x escapes to heap$" -} - -// self-assignments - -type Buffer struct { - arr [64]byte - arrPtr *[64]byte - buf1 []byte - buf2 []byte - str1 string - str2 string -} - -func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$" - b.buf1 = b.buf1[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2\]$" - b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf1\[1:2:3\]$" - b.buf1 = b.buf2[1:2] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2\]$" - b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment in b.buf1 = b.buf2\[1:2:3\]$" -} - -func (b *Buffer) bar() { // ERROR "leaking param: b$" - b.buf1 = b.arr[1:2] -} - -func (b *Buffer) arrayPtr() { // ERROR "\(\*Buffer\).arrayPtr b does not escape" - b.buf1 = b.arrPtr[1:2] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2\]$" - b.buf1 = b.arrPtr[1:2:3] // ERROR "\(\*Buffer\).arrayPtr ignoring self-assignment in b.buf1 = b.arrPtr\[1:2:3\]$" -} - -func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$" - b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str1\[1:2\]$" - b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment in b.str1 = b.str2\[1:2\]$" -} - -func (b *Buffer) bat() { // ERROR "leaking param content: b$" - o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$" - o.buf1 = b.buf1[1:2] - sink = o // ERROR "o escapes to heap$" -} - -func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$" - *sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment in \*sp = \(\*sp\)\[1:2\]$" - *bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment in \*bp = \(\*bp\)\[1:2\]$" -} - -type StructWithString struct { - p *int - s string -} - -// This is escape analysis false negative. -// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows -// to just x, and thus &i looks escaping. -func fieldFlowTracking() { - var x StructWithString - i := 0 // ERROR "moved to heap: i$" - x.p = &i - sink = x.s // ERROR "x.s escapes to heap$" -} - -// String operations. - -func slicebytetostring0() { - b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "slicebytetostring0 string\(b\) does not escape$" - _ = s -} - -func slicebytetostring1() { - b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "slicebytetostring1 string\(b\) does not escape$" - s1 := s[0:1] - _ = s1 -} - -func slicebytetostring2() { - b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "string\(b\) escapes to heap$" - s1 := s[0:1] // ERROR "moved to heap: s1$" - sink = &s1 // ERROR "&s1 escapes to heap$" -} - -func slicebytetostring3() { - b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$" - s := string(b) // ERROR "string\(b\) escapes to heap$" - s1 := s[0:1] - sink = s1 // ERROR "s1 escapes to heap$" -} - -func addstr0() { - s0 := "a" - s1 := "b" - s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$" - _ = s -} - -func addstr1() { - s0 := "a" - s1 := "b" - s := "c" - s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$" - _ = s -} - -func addstr2() { - b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$" - s0 := "a" - s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$" - _ = s -} - -func addstr3() { - s0 := "a" - s1 := "b" - s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$" - s2 := s[0:1] - sink = s2 // ERROR "s2 escapes to heap$" -} - -func intstring0() bool { - // string does not escape - x := '0' - s := string(x) // ERROR "intstring0 string\(x\) does not escape$" - return s == "0" -} - -func intstring1() string { - // string does not escape, but the buffer does - x := '0' - s := string(x) // ERROR "string\(x\) escapes to heap$" - return s -} - -func intstring2() { - // string escapes to heap - x := '0' - s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$" - sink = &s // ERROR "&s escapes to heap$" -} - -func stringtoslicebyte0() { - s := "foo" - x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$" - _ = x -} - -func stringtoslicebyte1() []byte { - s := "foo" - return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" -} - -func stringtoslicebyte2() { - s := "foo" - sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$" -} - -func stringtoslicerune0() { - s := "foo" - x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$" - _ = x -} - -func stringtoslicerune1() []rune { - s := "foo" - return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" -} - -func stringtoslicerune2() { - s := "foo" - sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$" -} - -func slicerunetostring0() { - r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$" - s := string(r) // ERROR "slicerunetostring0 string\(r\) does not escape$" - _ = s -} - -func slicerunetostring1() string { - r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$" - return string(r) // ERROR "string\(r\) escapes to heap$" -} - -func slicerunetostring2() { - r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$" - sink = string(r) // ERROR "string\(r\) escapes to heap$" -} - -func makemap0() { - m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$" - m[0] = 0 - m[1]++ - delete(m, 1) - sink = m[0] // ERROR "m\[0\] escapes to heap$" -} - -func makemap1() map[int]int { - return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" -} - -func makemap2() { - m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$" - sink = m // ERROR "m escapes to heap$" -} - -func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$" - return m["foo"] // ERROR "nonescapingEface .foo. does not escape$" -} - -func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$" - return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$" -} - -func issue10353() { - x := new(int) // ERROR "new\(int\) escapes to heap$" - issue10353a(x)() -} - -func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$" - return func() { // ERROR "func literal escapes to heap$" - println(*x) - } -} - -func issue10353b() { - var f func() - for { - x := new(int) // ERROR "new\(int\) escapes to heap$" - f = func() { // ERROR "func literal escapes to heap$" - println(*x) - } - } - _ = f -} - -func issue11387(x int) func() int { - f := func() int { return x } // ERROR "func literal escapes to heap" - slice1 := []func() int{f} // ERROR "\[\].* does not escape" - slice2 := make([]func() int, 1) // ERROR "make\(.*\) does not escape" - copy(slice2, slice1) - return slice2[0] -} - -func issue12397(x, y int) { // ERROR "moved to heap: y$" - // x does not escape below, because all relevant code is dead. - if false { - gxx = &x - } else { - gxx = &y - } - - if true { - gxx = &y - } else { - gxx = &x - } -} diff --git a/test/oldescape5.go b/test/oldescape5.go deleted file mode 100644 index 53d0ff80..00000000 --- a/test/oldescape5.go +++ /dev/null @@ -1,247 +0,0 @@ -// errorcheck -0 -m -l -newescape=false - -// Copyright 2012 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. - -// Test, using compiler diagnostic flags, that the escape analysis is working. -// Compiles but does not run. Inlining is disabled. - -package foo - -import "runtime" - -func noleak(p *int) int { // ERROR "p does not escape" - return *p -} - -func leaktoret(p *int) *int { // ERROR "leaking param: p to result" - return p -} - -func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2" - return p, p -} - -func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3" - return p, q -} - -func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2" - return leaktoret22(q, p) -} - -func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2" - r, s := leaktoret22(q, p) - return r, s -} - -func leaktoret22d(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" - r, s = leaktoret22(q, p) - return -} - -func leaktoret22e(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" - r, s = leaktoret22(q, p) - return r, s -} - -func leaktoret22f(p, q *int) (r, s *int) { // ERROR "leaking param: p to result s" "leaking param: q to result r" - rr, ss := leaktoret22(q, p) - return rr, ss -} - -var gp *int - -func leaktosink(p *int) *int { // ERROR "leaking param: p" - gp = p - return p -} - -func f1() { - var x int - p := noleak(&x) - _ = p -} - -func f2() { - var x int - p := leaktoret(&x) - _ = p -} - -func f3() { - var x int // ERROR "moved to heap: x" - p := leaktoret(&x) - gp = p -} - -func f4() { - var x int // ERROR "moved to heap: x" - p, q := leaktoret2(&x) - gp = p - gp = q -} - -func f5() { - var x int - leaktoret22(leaktoret2(&x)) -} - -func f6() { - var x int // ERROR "moved to heap: x" - px1, px2 := leaktoret22(leaktoret2(&x)) - gp = px1 - _ = px2 -} - -type T struct{ x int } - -func (t *T) Foo(u int) (*T, bool) { // ERROR "leaking param: t to result" - t.x += u - return t, true -} - -func f7() *T { - r, _ := new(T).Foo(42) // ERROR "new.T. escapes to heap" - return r -} - -func leakrecursive1(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q" - return leakrecursive2(q, p) -} - -func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaking param: q" - if *p > *q { - return leakrecursive1(q, p) - } - // without this, leakrecursive? are safe for p and q, b/c in fact their graph does not have leaking edges. - return p, q -} - -var global interface{} - -type T1 struct { - X *int -} - -type T2 struct { - Y *T1 -} - -func f8(p *T1) (k T2) { // ERROR "leaking param: p to result k" "leaking param: p" - if p == nil { - k = T2{} - return - } - - // should make p leak always - global = p // ERROR "p escapes to heap" - return T2{p} -} - -func f9() { - var j T1 // ERROR "moved to heap: j" - f8(&j) -} - -func f10() { - // These don't escape but are too big for the stack - var x [1 << 30]byte // ERROR "moved to heap: x" - var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1 << 30\) escapes to heap" - _ = x[0] + y[0] -} - -// Test for issue 19687 (passing to unnamed parameters does not escape). -func f11(**int) { -} -func f12(_ **int) { -} -func f13() { - var x *int - f11(&x) - f12(&x) - runtime.KeepAlive(&x) // ERROR "&x does not escape" -} - -// Test for issue 24305 (passing to unnamed receivers does not escape). -type U int - -func (*U) M() {} -func (_ *U) N() {} - -func _() { - var u U - u.M() - u.N() -} - -// Issue 24730: taking address in a loop causes unnecessary escape -type T24730 struct { - x [64]byte -} - -func (t *T24730) g() { // ERROR "t does not escape" - y := t.x[:] - for i := range t.x[:] { - y = t.x[:] - y[i] = 1 - } - - var z *byte - for i := range t.x[:] { - z = &t.x[i] - *z = 2 - } -} - -// Issue 15730: copy causes unnecessary escape - -var sink []byte -var sink2 []int -var sink3 []*int - -func f15730a(args ...interface{}) { // ERROR "args does not escape" - for _, arg := range args { - switch a := arg.(type) { - case string: - copy(sink, a) - } - } -} - -func f15730b(args ...interface{}) { // ERROR "args does not escape" - for _, arg := range args { - switch a := arg.(type) { - case []int: - copy(sink2, a) - } - } -} - -func f15730c(args ...interface{}) { // ERROR "leaking param content: args" - for _, arg := range args { - switch a := arg.(type) { - case []*int: - // copy pointerful data should cause escape - copy(sink3, a) - } - } -} - -// Issue 29000: unnamed parameter is not handled correctly - -var sink4 interface{} -var alwaysFalse = false - -func f29000(_ int, x interface{}) { // ERROR "leaking param: x" - sink4 = x - if alwaysFalse { - g29000() - } -} - -func g29000() { - x := 1 - f29000(2, x) // ERROR "x escapes to heap" -} diff --git a/test/oldescape_calls.go b/test/oldescape_calls.go deleted file mode 100644 index 715e8321..00000000 --- a/test/oldescape_calls.go +++ /dev/null @@ -1,54 +0,0 @@ -// errorcheck -0 -m -l -newescape=false - -// Copyright 2015 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. - -// Test escape analysis for function parameters. - -// In this test almost everything is BAD except the simplest cases -// where input directly flows to output. - -package foo - -func f(buf []byte) []byte { // ERROR "leaking param: buf to result ~r1 level=0$" - return buf -} - -func g(*byte) string - -func h(e int) { - var x [32]byte // ERROR "moved to heap: x$" - g(&f(x[:])[0]) -} - -type Node struct { - s string - left, right *Node -} - -func walk(np **Node) int { // ERROR "leaking param content: np" - n := *np - w := len(n.s) - if n == nil { - return 0 - } - wl := walk(&n.left) - wr := walk(&n.right) - if wl < wr { - n.left, n.right = n.right, n.left - wl, wr = wr, wl - } - *np = n - return w + wl + wr -} - -// Test for bug where func var f used prototype's escape analysis results. -func prototype(xyz []string) {} // ERROR "prototype xyz does not escape" -func bar() { - var got [][]string - 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" -} diff --git a/test/oldescape_closure.go b/test/oldescape_closure.go deleted file mode 100644 index 386605df..00000000 --- a/test/oldescape_closure.go +++ /dev/null @@ -1,173 +0,0 @@ -// errorcheck -0 -m -l -newescape=false - -// Copyright 2015 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. - -// Test escape analysis for closure arguments. - -package escape - -var sink interface{} - -func ClosureCallArgs0() { - x := 0 // ERROR "moved to heap: x" - func(p *int) { // ERROR "p does not escape" "func literal does not escape" - *p = 1 - // BAD: x should not escape to heap here - }(&x) -} - -func ClosureCallArgs1() { - x := 0 // ERROR "moved to heap: x" - for { - func(p *int) { // ERROR "p does not escape" "func literal does not escape" - *p = 1 - // BAD: x should not escape to heap here - }(&x) - } -} - -func ClosureCallArgs2() { - for { - // BAD: x should not escape here - x := 0 // ERROR "moved to heap: x" - func(p *int) { // ERROR "p does not escape" "func literal does not escape" - *p = 1 - }(&x) - } -} - -func ClosureCallArgs3() { - x := 0 // ERROR "moved to heap: x" - func(p *int) { // ERROR "leaking param: p" "func literal does not escape" - sink = p // ERROR "p escapes to heap" - }(&x) -} - -func ClosureCallArgs4() { - // BAD: x should not leak here - x := 0 // ERROR "moved to heap: x" - _ = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" - return p - }(&x) -} - -func ClosureCallArgs5() { - x := 0 // ERROR "moved to heap: x" - sink = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" "\(func literal\)\(&x\) escapes to heap" - return p - }(&x) -} - -func ClosureCallArgs6() { - x := 0 // ERROR "moved to heap: x" - func(p *int) { // ERROR "moved to heap: p" "func literal does not escape" - sink = &p // ERROR "&p escapes to heap" - }(&x) -} - -func ClosureCallArgs7() { - var pp *int - for { - x := 0 // ERROR "moved to heap: x" - func(p *int) { // ERROR "leaking param: p" "func literal does not escape" - pp = p - }(&x) - } - _ = pp -} - -func ClosureCallArgs8() { - x := 0 // ERROR "moved to heap: x" - defer func(p *int) { // ERROR "p does not escape" "func literal does not escape" - *p = 1 - // BAD: x should not escape to heap here - }(&x) -} - -func ClosureCallArgs9() { - // BAD: x should not leak - x := 0 // ERROR "moved to heap: x" - for { - defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape" - *p = 1 - }(&x) - } -} - -func ClosureCallArgs10() { - for { - x := 0 // ERROR "moved to heap: x" - defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape" - *p = 1 - }(&x) - } -} - -func ClosureCallArgs11() { - x := 0 // ERROR "moved to heap: x" - defer func(p *int) { // ERROR "leaking param: p" "func literal does not escape" - sink = p // ERROR "p escapes to heap" - }(&x) -} - -func ClosureCallArgs12() { - // BAD: x should not leak - x := 0 // ERROR "moved to heap: x" - defer func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape" - return p - }(&x) -} - -func ClosureCallArgs13() { - x := 0 // ERROR "moved to heap: x" - defer func(p *int) { // ERROR "moved to heap: p" "func literal does not escape" - sink = &p // ERROR "&p escapes to heap" - }(&x) -} - -func ClosureCallArgs14() { - x := 0 // ERROR "moved to heap: x" - // BAD: &x should not escape here - p := &x // ERROR "moved to heap: p" - _ = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" - return *p - // BAD: p should not escape here - }(&p) -} - -func ClosureCallArgs15() { - x := 0 // ERROR "moved to heap: x" - p := &x // ERROR "moved to heap: p" - sink = func(p **int) *int { // ERROR "leaking param: p to result ~r1 level=1" "func literal does not escape" "\(func literal\)\(&p\) escapes to heap" - return *p - // BAD: p should not escape here - }(&p) -} - -func ClosureLeak1(s string) string { // ERROR "ClosureLeak1 s does not escape" - t := s + "YYYY" // ERROR "escapes to heap" - return ClosureLeak1a(t) // ERROR "ClosureLeak1 ... argument does not escape" -} - -// See #14409 -- returning part of captured var leaks it. -func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" - return func() string { // ERROR "ClosureLeak1a func literal does not escape" - return a[0] - }() -} - -func ClosureLeak2(s string) string { // ERROR "ClosureLeak2 s does not escape" - t := s + "YYYY" // ERROR "escapes to heap" - c := ClosureLeak2a(t) // ERROR "ClosureLeak2 ... argument does not escape" - return c -} -func ClosureLeak2a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" - return ClosureLeak2b(func() string { // ERROR "ClosureLeak2a func literal does not escape" - return a[0] - }) -} -func ClosureLeak2b(f func() string) string { // ERROR "leaking param: f to result ~r1 level=1" - return f() -} diff --git a/test/oldescape_field.go b/test/oldescape_field.go deleted file mode 100644 index e4213aaf..00000000 --- a/test/oldescape_field.go +++ /dev/null @@ -1,174 +0,0 @@ -// errorcheck -0 -m -l -newescape=false - -// Copyright 2015 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. - -// Test escape analysis with respect to field assignments. - -package escape - -var sink interface{} - -type X struct { - p1 *int - p2 *int - a [2]*int -} - -type Y struct { - x X -} - -func field0() { - i := 0 // ERROR "moved to heap: i$" - var x X - x.p1 = &i - sink = x.p1 // ERROR "x\.p1 escapes to heap" -} - -func field1() { - i := 0 // ERROR "moved to heap: i$" - var x X - // BAD: &i should not escape - x.p1 = &i - sink = x.p2 // ERROR "x\.p2 escapes to heap" -} - -func field3() { - i := 0 // ERROR "moved to heap: i$" - var x X - x.p1 = &i - sink = x // ERROR "x escapes to heap" -} - -func field4() { - i := 0 // ERROR "moved to heap: i$" - var y Y - y.x.p1 = &i - x := y.x - sink = x // ERROR "x escapes to heap" -} - -func field5() { - i := 0 // ERROR "moved to heap: i$" - var x X - // BAD: &i should not escape here - x.a[0] = &i - sink = x.a[1] // ERROR "x\.a\[1\] escapes to heap" -} - -// BAD: we are not leaking param x, only x.p2 -func field6(x *X) { // ERROR "leaking param content: x$" - sink = x.p2 // ERROR "x\.p2 escapes to heap" -} - -func field6a() { - i := 0 // ERROR "moved to heap: i$" - var x X - // BAD: &i should not escape - x.p1 = &i - field6(&x) -} - -func field7() { - i := 0 - var y Y - y.x.p1 = &i - x := y.x - var y1 Y - y1.x = x - _ = y1.x.p1 -} - -func field8() { - i := 0 // ERROR "moved to heap: i$" - var y Y - y.x.p1 = &i - x := y.x - var y1 Y - y1.x = x - sink = y1.x.p1 // ERROR "y1\.x\.p1 escapes to heap" -} - -func field9() { - i := 0 // ERROR "moved to heap: i$" - var y Y - y.x.p1 = &i - x := y.x - var y1 Y - y1.x = x - sink = y1.x // ERROR "y1\.x escapes to heap" -} - -func field10() { - i := 0 // ERROR "moved to heap: i$" - var y Y - // BAD: &i should not escape - y.x.p1 = &i - x := y.x - var y1 Y - y1.x = x - sink = y1.x.p2 // ERROR "y1\.x\.p2 escapes to heap" -} - -func field11() { - i := 0 // ERROR "moved to heap: i$" - x := X{p1: &i} - sink = x.p1 // ERROR "x\.p1 escapes to heap" -} - -func field12() { - i := 0 // ERROR "moved to heap: i$" - // BAD: &i should not escape - x := X{p1: &i} - sink = x.p2 // ERROR "x\.p2 escapes to heap" -} - -func field13() { - i := 0 // ERROR "moved to heap: i$" - x := &X{p1: &i} // ERROR "field13 &X literal does not escape$" - sink = x.p1 // ERROR "x\.p1 escapes to heap" -} - -func field14() { - i := 0 // ERROR "moved to heap: i$" - // BAD: &i should not escape - x := &X{p1: &i} // ERROR "field14 &X literal does not escape$" - sink = x.p2 // ERROR "x\.p2 escapes to heap" -} - -func field15() { - i := 0 // ERROR "moved to heap: i$" - x := &X{p1: &i} // ERROR "&X literal escapes to heap$" - sink = x // ERROR "x escapes to heap" -} - -func field16() { - i := 0 // ERROR "moved to heap: i$" - var x X - // BAD: &i should not escape - x.p1 = &i - var iface interface{} = x // ERROR "x escapes to heap" - x1 := iface.(X) - sink = x1.p2 // ERROR "x1\.p2 escapes to heap" -} - -func field17() { - i := 0 // ERROR "moved to heap: i$" - var x X - x.p1 = &i - var iface interface{} = x // ERROR "x escapes to heap" - x1 := iface.(X) - sink = x1.p1 // ERROR "x1\.p1 escapes to heap" -} - -func field18() { - i := 0 // ERROR "moved to heap: i$" - var x X - // BAD: &i should not escape - x.p1 = &i - var iface interface{} = x // ERROR "x escapes to heap" - y, _ := iface.(Y) // Put X, but extracted Y. The cast will fail, so y is zero initialized. - sink = y // ERROR "y escapes to heap" -} diff --git a/test/oldescape_iface.go b/test/oldescape_iface.go deleted file mode 100644 index 88502df9..00000000 --- a/test/oldescape_iface.go +++ /dev/null @@ -1,261 +0,0 @@ -// errorcheck -0 -m -l -newescape=false - -// Copyright 2015 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. - -// Test escape analysis for interface conversions. - -package escape - -var sink interface{} - -type M interface { - M() -} - -func mescapes(m M) { // ERROR "leaking param: m" - sink = m // ERROR "m escapes to heap" -} - -func mdoesnotescape(m M) { // ERROR "m does not escape" -} - -// Tests for type stored directly in iface and with value receiver method. -type M0 struct { - p *int -} - -func (M0) M() { -} - -func efaceEscape0() { - { - i := 0 - v := M0{&i} - var x M = v // ERROR "v does not escape" - _ = x - } - { - i := 0 // ERROR "moved to heap: i" - v := M0{&i} - var x M = v // ERROR "v escapes to heap" - sink = x // ERROR "x escapes to heap" - } - { - i := 0 - v := M0{&i} - var x M = v // ERROR "v does not escape" - v1 := x.(M0) - _ = v1 - } - { - i := 0 // ERROR "moved to heap: i" - v := M0{&i} - // BAD: v does not escape to heap here - var x M = v // ERROR "v escapes to heap" - v1 := x.(M0) - sink = v1 // ERROR "v1 escapes to heap" - } - { - i := 0 // ERROR "moved to heap: i" - v := M0{&i} - // 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" - v := M0{&i} - var x M = v // ERROR "v escapes to heap" - mescapes(x) - } - { - i := 0 - v := M0{&i} - var x M = v // ERROR "v does not escape" - mdoesnotescape(x) - } -} - -// Tests for type stored indirectly in iface and with value receiver method. -type M1 struct { - p *int - x int -} - -func (M1) M() { -} - -func efaceEscape1() { - { - i := 0 - v := M1{&i, 0} - var x M = v // ERROR "v does not escape" - _ = x - } - { - i := 0 // ERROR "moved to heap: i" - v := M1{&i, 0} - var x M = v // ERROR "v escapes to heap" - sink = x // ERROR "x escapes to heap" - } - { - i := 0 - v := M1{&i, 0} - var x M = v // ERROR "v does not escape" - v1 := x.(M1) - _ = v1 - } - { - 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" - v1 := x.(M1) - sink = v1 // ERROR "v1 escapes to heap" - } - { - 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" - v := M1{&i, 0} - 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" - mdoesnotescape(x) - } -} - -// Tests for type stored directly in iface and with pointer receiver method. -type M2 struct { - p *int -} - -func (*M2) M() { -} - -func efaceEscape2() { - { - i := 0 - v := &M2{&i} // ERROR "&M2 literal does not escape" - var x M = v // ERROR "v does not escape" - _ = x - } - { - i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&M2 literal escapes to heap" - var x M = v // ERROR "v escapes to heap" - sink = x // ERROR "x escapes to heap" - } - { - i := 0 - v := &M2{&i} // ERROR "&M2 literal does not escape" - var x M = v // ERROR "v does not escape" - v1 := x.(*M2) - _ = v1 - } - { - i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&M2 literal escapes to heap" - // BAD: v does not escape to heap here - var x M = v // ERROR "v escapes to heap" - v1 := x.(*M2) - sink = v1 // ERROR "v1 escapes to heap" - } - { - i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&M2 literal does not escape" - // BAD: v does not escape to heap here - var x M = v // ERROR "v does not escape" - v1 := x.(*M2) - sink = *v1 // ERROR "v1 escapes to heap" - } - { - i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&M2 literal does not escape" - // BAD: v does not escape to heap here - var x M = v // ERROR "v does not escape" - v1, ok := x.(*M2) - sink = *v1 // ERROR "v1 escapes to heap" - _ = ok - } - { - i := 0 // ERROR "moved to heap: i" - v := &M2{&i} // ERROR "&M2 literal escapes to heap" - // 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" - v := &M2{&i} // ERROR "&M2 literal escapes to heap" - var x M = v // ERROR "v escapes to heap" - mescapes(x) - } - { - i := 0 - v := &M2{&i} // ERROR "&M2 literal does not escape" - var x M = v // ERROR "v does not escape" - mdoesnotescape(x) - } -} - -type T1 struct { - p *int -} - -type T2 struct { - T1 T1 -} - -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{ - T1: *(x.(*T1)), // ERROR "&T2 literal escapes to heap" - } -} - -func dotTypeEscape2() { // #13805, #15796 - { - i := 0 - j := 0 - var v int - var ok bool - var x interface{} = i // ERROR "i does not escape" - var y interface{} = j // ERROR "j does not escape" - - *(&v) = x.(int) - *(&v), *(&ok) = y.(int) - } - { - i := 0 - j := 0 - var ok bool - 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, *(&ok) = y.(int) - } - { - i := 0 // ERROR "moved to heap: i" - j := 0 // ERROR "moved to heap: j" - var ok bool - var x interface{} = &i // ERROR "&i escapes to heap" - var y interface{} = &j // ERROR "&j escapes to heap" - - sink = x.(*int) // ERROR "x.\(\*int\) escapes to heap" - sink, *(&ok) = y.(*int) - } -} diff --git a/test/oldescape_linkname.go b/test/oldescape_linkname.go deleted file mode 100644 index f99df1bb..00000000 --- a/test/oldescape_linkname.go +++ /dev/null @@ -1,15 +0,0 @@ -// errorcheckandrundir -0 -m -l=4 -newescape=false - -// Copyright 2010 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. - -// Tests that linknames are included in export data (issue 18167). -package ignored - -/* -Without CL 33911, this test would fail with the following error: - -main.main: relocation target linkname2.byteIndex not defined -main.main: undefined: "linkname2.byteIndex" -*/ diff --git a/test/oldescape_param.go b/test/oldescape_param.go deleted file mode 100644 index 3a3eee2a..00000000 --- a/test/oldescape_param.go +++ /dev/null @@ -1,441 +0,0 @@ -// errorcheck -0 -m -l -newescape=false - -// Copyright 2015 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. - -// Test escape analysis for function parameters. - -// In this test almost everything is BAD except the simplest cases -// where input directly flows to output. - -package escape - -func zero() int { return 0 } - -var sink interface{} - -// in -> out -func param0(p *int) *int { // ERROR "leaking param: p to result ~r1" - return p -} - -func caller0a() { - i := 0 - _ = param0(&i) -} - -func caller0b() { - i := 0 // ERROR "moved to heap: i$" - sink = param0(&i) // ERROR "param0\(&i\) escapes to heap" -} - -// in, in -> out, out -func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r2" "leaking param: p2 to result ~r3" - return p1, p2 -} - -func caller1() { - i := 0 // ERROR "moved to heap: i$" - j := 0 - sink, _ = param1(&i, &j) -} - -// in -> other in -func param2(p1 *int, p2 **int) { // ERROR "leaking param: p1$" "param2 p2 does not escape$" - *p2 = p1 -} - -func caller2a() { - i := 0 // ERROR "moved to heap: i$" - var p *int - param2(&i, &p) - _ = p -} - -func caller2b() { - i := 0 // ERROR "moved to heap: i$" - var p *int - param2(&i, &p) - sink = p // ERROR "p escapes to heap$" -} - -func paramArraySelfAssign(p *PairOfPairs) { // ERROR "p does not escape" - p.pairs[0] = p.pairs[1] // ERROR "ignoring self-assignment in p.pairs\[0\] = p.pairs\[1\]" -} - -func paramArraySelfAssignUnsafeIndex(p *PairOfPairs) { // ERROR "leaking param content: p" - // Function call inside index disables self-assignment case to trigger. - p.pairs[zero()] = p.pairs[1] - p.pairs[zero()+1] = p.pairs[1] -} - -type PairOfPairs struct { - pairs [2]*Pair -} - -type BoxedPair struct { - pair *Pair -} - -type WrappedPair struct { - pair Pair -} - -func leakParam(x interface{}) { // ERROR "leaking param: x" - sink = x -} - -func sinkAfterSelfAssignment1(box *BoxedPair) { // ERROR "leaking param content: box" - box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" - sink = box.pair.p2 // ERROR "box.pair.p2 escapes to heap" -} - -func sinkAfterSelfAssignment2(box *BoxedPair) { // ERROR "leaking param content: box" - box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" - sink = box.pair // ERROR "box.pair escapes to heap" -} - -func sinkAfterSelfAssignment3(box *BoxedPair) { // ERROR "leaking param content: box" - box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" - leakParam(box.pair.p2) // ERROR "box.pair.p2 escapes to heap" -} - -func sinkAfterSelfAssignment4(box *BoxedPair) { // ERROR "leaking param content: box" - box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" - leakParam(box.pair) // ERROR "box.pair escapes to heap" -} - -func selfAssignmentAndUnrelated(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape" - box1.pair.p1 = box1.pair.p2 // ERROR "ignoring self-assignment in box1.pair.p1 = box1.pair.p2" - leakParam(box2.pair.p2) // ERROR "box2.pair.p2 escapes to heap" -} - -func notSelfAssignment1(box1, box2 *BoxedPair) { // ERROR "leaking param content: box2" "box1 does not escape" - box1.pair.p1 = box2.pair.p1 -} - -func notSelfAssignment2(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape" - p1.pairs[0] = p2.pairs[1] -} - -func notSelfAssignment3(p1, p2 *PairOfPairs) { // ERROR "leaking param content: p2" "p1 does not escape" - p1.pairs[0].p1 = p2.pairs[1].p1 -} - -func boxedPairSelfAssign(box *BoxedPair) { // ERROR "box does not escape" - box.pair.p1 = box.pair.p2 // ERROR "ignoring self-assignment in box.pair.p1 = box.pair.p2" -} - -func wrappedPairSelfAssign(w *WrappedPair) { // ERROR "w does not escape" - w.pair.p1 = w.pair.p2 // ERROR "ignoring self-assignment in w.pair.p1 = w.pair.p2" -} - -// in -> in -type Pair struct { - p1 *int - p2 *int -} - -func param3(p *Pair) { // ERROR "param3 p does not escape" - p.p1 = p.p2 // ERROR "param3 ignoring self-assignment in p.p1 = p.p2" -} - -func caller3a() { - i := 0 - j := 0 - p := Pair{&i, &j} - param3(&p) - _ = p -} - -func caller3b() { - 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$" -} - -// in -> rcvr -func (p *Pair) param4(i *int) { // ERROR "\(\*Pair\).param4 p does not escape$" "leaking param: i$" - p.p1 = i -} - -func caller4a() { - i := 0 // ERROR "moved to heap: i$" - p := Pair{} - p.param4(&i) - _ = p -} - -func caller4b() { - i := 0 // ERROR "moved to heap: i$" - p := Pair{} - p.param4(&i) - sink = p // ERROR "p escapes to heap$" -} - -// in -> heap -func param5(i *int) { // ERROR "leaking param: i$" - sink = i // ERROR "i escapes to heap$" -} - -func caller5() { - i := 0 // ERROR "moved to heap: i$" - param5(&i) -} - -// *in -> heap -func param6(i ***int) { // ERROR "leaking param content: i$" - sink = *i // ERROR "\*i escapes to heap$" -} - -func caller6a() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p$" - p2 := &p - param6(&p2) -} - -// **in -> heap -func param7(i ***int) { // ERROR "leaking param content: i$" - sink = **i // ERROR "\* \(\*i\) escapes to heap" -} - -func caller7() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p$" - p2 := &p - param7(&p2) -} - -// **in -> heap -func param8(i **int) { // ERROR "param8 i does not escape$" - sink = **i // ERROR "\* \(\*i\) escapes to heap" -} - -func caller8() { - i := 0 - p := &i - param8(&p) -} - -// *in -> out -func param9(p ***int) **int { // ERROR "leaking param: p to result ~r1 level=1" - return *p -} - -func caller9a() { - i := 0 - p := &i - p2 := &p - _ = param9(&p2) -} - -func caller9b() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p$" - p2 := &p - sink = param9(&p2) // ERROR "param9\(&p2\) escapes to heap" -} - -// **in -> out -func param10(p ***int) *int { // ERROR "leaking param: p to result ~r1 level=2" - return **p -} - -func caller10a() { - i := 0 - p := &i - p2 := &p - _ = param10(&p2) -} - -func caller10b() { - i := 0 // ERROR "moved to heap: i$" - p := &i - p2 := &p - sink = param10(&p2) // ERROR "param10\(&p2\) escapes to heap" -} - -// in escapes to heap (address of param taken and returned) -func param11(i **int) ***int { // ERROR "moved to heap: i$" - return &i -} - -func caller11a() { - 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$" - sink = param11(&p) // ERROR "param11\(&p\) escapes to heap" -} - -func caller11c() { // GOOD - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p" - sink = *param11(&p) // ERROR "\*param11\(&p\) escapes to heap" -} - -func caller11d() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p" - p2 := &p - sink = param11(p2) // ERROR "param11\(p2\) escapes to heap" -} - -// &in -> rcvr -type Indir struct { - p ***int -} - -func (r *Indir) param12(i **int) { // ERROR "\(\*Indir\).param12 r does not escape$" "moved to heap: i$" - r.p = &i -} - -func caller12a() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p$" - var r Indir - r.param12(&p) - _ = r -} - -func caller12b() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p$" - r := &Indir{} // ERROR "caller12b &Indir literal does not escape$" - r.param12(&p) - _ = r -} - -func caller12c() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p$" - r := Indir{} - r.param12(&p) - sink = r // ERROR "r escapes to heap$" -} - -func caller12d() { - i := 0 // ERROR "moved to heap: i$" - p := &i // ERROR "moved to heap: p$" - r := Indir{} - r.param12(&p) - sink = **r.p // ERROR "\* \(\*r\.p\) escapes to heap" -} - -// in -> value rcvr -type Val struct { - p **int -} - -func (v Val) param13(i *int) { // ERROR "Val.param13 v does not escape$" "leaking param: i$" - *v.p = i -} - -func caller13a() { - i := 0 // ERROR "moved to heap: i$" - var p *int - var v Val - v.p = &p - v.param13(&i) - _ = v -} - -func caller13b() { - i := 0 // ERROR "moved to heap: i$" - var p *int - v := Val{&p} - v.param13(&i) - _ = v -} - -func caller13c() { - i := 0 // ERROR "moved to heap: i$" - var p *int - v := &Val{&p} // ERROR "caller13c &Val literal does not escape$" - v.param13(&i) - _ = v -} - -func caller13d() { - i := 0 // ERROR "moved to heap: i$" - var p *int // ERROR "moved to heap: p$" - var v Val - v.p = &p - v.param13(&i) - sink = v // ERROR "v escapes to heap$" -} - -func caller13e() { - i := 0 // ERROR "moved to heap: i$" - var p *int // ERROR "moved to heap: p$" - v := Val{&p} - v.param13(&i) - sink = v // ERROR "v escapes to heap$" -} - -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.param13(&i) - sink = v // ERROR "v escapes to heap$" -} - -func caller13g() { - i := 0 // ERROR "moved to heap: i$" - var p *int - v := Val{&p} - v.param13(&i) - sink = *v.p // ERROR "\*v\.p escapes to heap" -} - -func caller13h() { - i := 0 // ERROR "moved to heap: i$" - var p *int - v := &Val{&p} // ERROR "caller13h &Val literal does not escape$" - v.param13(&i) - sink = **v.p // ERROR "\* \(\*v\.p\) escapes to heap" -} - -type Node struct { - p *Node -} - -var Sink *Node - -func f(x *Node) { // ERROR "leaking param content: x" - Sink = &Node{x.p} // ERROR "&Node literal escapes to heap" -} - -func g(x *Node) *Node { // ERROR "leaking param: x to result ~r1 level=0" - return &Node{x.p} // ERROR "&Node literal escapes to heap" -} - -func h(x *Node) { // ERROR "leaking param: x" - y := &Node{x} // ERROR "h &Node literal does not escape" - Sink = g(y) - f(y) -} - -// interface(in) -> out -// See also issue 29353. - -// Convert to a non-direct interface, require an allocation and -// copy x to heap (not to result). -func param14a(x [4]*int) interface{} { // ERROR "leaking param: x$" - return x // ERROR "x escapes to heap" -} - -// Convert to a direct interface, does not need an allocation. -// So x only leaks to result. -func param14b(x *int) interface{} { // ERROR "leaking param: x to result ~r1 level=0" - return x // ERROR "x escapes to heap" -} diff --git a/test/oldescape_struct_return.go b/test/oldescape_struct_return.go deleted file mode 100644 index 5088cf86..00000000 --- a/test/oldescape_struct_return.go +++ /dev/null @@ -1,74 +0,0 @@ -// errorcheck -0 -m -l -newescape=false - -// Copyright 2015 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. - -// Test escape analysis for function parameters. - -package foo - -var Ssink *string - -type U struct { - _sp *string - _spp **string -} - -func A(sp *string, spp **string) U { // ERROR "leaking param: sp to result ~r2 level=0$" "leaking param: spp to result ~r2 level=0$" - return U{sp, spp} -} - -func B(spp **string) U { // ERROR "leaking param: spp to result ~r1 level=0$" "leaking param: spp to result ~r1 level=1$" - return U{*spp, spp} -} - -func tA1() { - s := "cat" - sp := &s - spp := &sp - u := A(sp, spp) - _ = u - println(s) -} - -func tA2() { - s := "cat" - sp := &s - spp := &sp - u := A(sp, spp) - println(*u._sp) -} - -func tA3() { - s := "cat" - sp := &s - spp := &sp - u := A(sp, spp) - println(**u._spp) -} - -func tB1() { - s := "cat" - sp := &s - spp := &sp - u := B(spp) - _ = u - println(s) -} - -func tB2() { - s := "cat" - sp := &s - spp := &sp - u := B(spp) - println(*u._sp) -} - -func tB3() { - s := "cat" - sp := &s - spp := &sp - u := B(spp) - println(**u._spp) -} diff --git a/test/opt_branchlikely.go b/test/opt_branchlikely.go index 84de3217..884c3491 100644 --- a/test/opt_branchlikely.go +++ b/test/opt_branchlikely.go @@ -1,6 +1,6 @@ // +build amd64 // errorcheck -0 -d=ssa/likelyadjust/debug=1,ssa/insert_resched_checks/off -// rescheduling check insertion is turend off because the inserted conditional branches perturb the errorcheck +// rescheduling check insertion is turned off because the inserted conditional branches perturb the errorcheck // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/prove.go b/test/prove.go index 6e92b9ee..d37021d2 100644 --- a/test/prove.go +++ b/test/prove.go @@ -81,7 +81,7 @@ func f4a(a, b, c int) int { if a == b { // ERROR "Disproved Eq64$" return 47 } - if a > b { // ERROR "Disproved Greater64$" + if a > b { // ERROR "Disproved Less64$" return 50 } if a < b { // ERROR "Proved Less64$" @@ -141,7 +141,7 @@ func f4d(a, b, c int) int { func f4e(a, b, c int) int { if a < b { - if b > a { // ERROR "Proved Greater64$" + if b > a { // ERROR "Proved Less64$" return 101 } return 103 @@ -157,7 +157,7 @@ func f4f(a, b, c int) int { } return 114 } - if b >= a { // ERROR "Proved Geq64$" + if b >= a { // ERROR "Proved Leq64$" if b == a { // ERROR "Proved Eq64$" return 118 } @@ -194,7 +194,7 @@ func f6b(a uint8) int { } func f6x(a uint8) int { - if a > a { // ERROR "Disproved Greater8U$" + if a > a { // ERROR "Disproved Less8U$" return 143 } return 151 @@ -208,7 +208,7 @@ func f6d(a uint8) int { } func f6e(a uint8) int { - if a >= a { // ERROR "Proved Geq8U$" + if a >= a { // ERROR "Proved Leq8U$" return 149 } return 151 @@ -299,12 +299,12 @@ func f13a(a, b, c int, x bool) int { } } if x { - if a >= 12 { // ERROR "Proved Geq64$" + if a >= 12 { // ERROR "Proved Leq64$" return 4 } } if x { - if a > 12 { // ERROR "Proved Greater64$" + if a > 12 { // ERROR "Proved Less64$" return 5 } } @@ -331,12 +331,12 @@ func f13b(a int, x bool) int { } } if x { - if a >= -9 { // ERROR "Proved Geq64$" + if a >= -9 { // ERROR "Proved Leq64$" return 10 } } if x { - if a > -9 { // ERROR "Disproved Greater64$" + if a > -9 { // ERROR "Disproved Less64$" return 11 } } @@ -363,12 +363,12 @@ func f13c(a int, x bool) int { } } if x { - if a >= 90 { // ERROR "Disproved Geq64$" + if a >= 90 { // ERROR "Disproved Leq64$" return 16 } } if x { - if a > 90 { // ERROR "Disproved Greater64$" + if a > 90 { // ERROR "Disproved Less64$" return 17 } } @@ -388,7 +388,7 @@ func f13d(a int) int { func f13e(a int) int { if a > 9 { - if a > 5 { // ERROR "Proved Greater64$" + if a > 5 { // ERROR "Proved Less64$" return 1 } } @@ -432,7 +432,7 @@ func f13i(a uint) int { if a == 0 { return 1 } - if a > 0 { // ERROR "Proved Greater64U$" + if a > 0 { // ERROR "Proved Less64U$" return 2 } return 3 @@ -477,13 +477,13 @@ func f18(b []int, x int, y uint) { _ = b[x] _ = b[y] - if x > len(b) { // ERROR "Disproved Greater64$" + if x > len(b) { // ERROR "Disproved Less64$" return } - if y > uint(len(b)) { // ERROR "Disproved Greater64U$" + if y > uint(len(b)) { // ERROR "Disproved Less64U$" return } - if int(y) > len(b) { // ERROR "Disproved Greater64$" + if int(y) > len(b) { // ERROR "Disproved Less64$" return } } @@ -497,7 +497,7 @@ func f19() (e int64, err error) { } last := len(stack) - 1 e = stack[last] - // Buggy compiler prints "Disproved Geq64" for the next line. + // Buggy compiler prints "Disproved Leq64" for the next line. stack = stack[:last] // ERROR "Proved IsSliceInBounds" return e, nil } @@ -507,19 +507,19 @@ func sm1(b []int, x int) { useSlice(b[2:8]) // ERROR "Proved slicemask not needed$" // Test non-constant argument with known limits. if cap(b) > 10 { - useSlice(b[2:]) // ERROR "Proved slicemask not needed$" + useSlice(b[2:]) } } func lim1(x, y, z int) { // Test relations between signed and unsigned limits. if x > 5 { - if uint(x) > 5 { // ERROR "Proved Greater64U$" + if uint(x) > 5 { // ERROR "Proved Less64U$" return } } if y >= 0 && y < 4 { - if uint(y) > 4 { // ERROR "Disproved Greater64U$" + if uint(y) > 4 { // ERROR "Disproved Less64U$" return } if uint(y) < 5 { // ERROR "Proved Less64U$" @@ -544,13 +544,13 @@ func fence1(b []int, x, y int) { } if len(b) < cap(b) { // This eliminates the growslice path. - b = append(b, 1) // ERROR "Disproved Greater64U$" + b = append(b, 1) // ERROR "Disproved Less64U$" } } func fence2(x, y int) { if x-1 < y { - if x > y { // ERROR "Disproved Greater64$" + if x > y { // ERROR "Disproved Less64$" return } } @@ -593,18 +593,18 @@ func fence4(x, y int64) { func trans1(x, y int64) { if x > 5 { if y > x { - if y > 2 { // ERROR "Proved Greater64$" + if y > 2 { // ERROR "Proved Less64$" return } } else if y == x { - if y > 5 { // ERROR "Proved Greater64$" + if y > 5 { // ERROR "Proved Less64$" return } } } if x >= 10 { if y > x { - if y > 10 { // ERROR "Proved Greater64$" + if y > 10 { // ERROR "Proved Less64$" return } } @@ -678,6 +678,30 @@ func oforuntil(b []int) { } } +func atexit(foobar []func()) { + for i := len(foobar) - 1; i >= 0; i-- { // ERROR "Induction variable: limits \[0,\?\], increment 1" + f := foobar[i] + foobar = foobar[:i] // ERROR "IsSliceInBounds" + f() + } +} + +func make1(n int) []int { + s := make([]int, n) + for i := 0; i < n; i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1" + s[i] = 1 // ERROR "Proved IsInBounds$" + } + return s +} + +func make2(n int) []int { + s := make([]int, n) + for i := range s { // ERROR "Induction variable: limits \[0,\?\), increment 1" + s[i] = 1 // ERROR "Proved IsInBounds$" + } + return s +} + // The range tests below test the index variable of range loops. // range1 compiles to the "efficiently indexable" form of a range loop. @@ -687,7 +711,7 @@ func range1(b []int) { if i < len(b) { // ERROR "Proved Less64$" println("x") } - if i >= 0 { // ERROR "Proved Geq64$" + if i >= 0 { // ERROR "Proved Leq64$" println("x") } } @@ -700,7 +724,7 @@ func range2(b [][32]int) { if i < len(b) { // ERROR "Proved Less64$" println("x") } - if i >= 0 { // ERROR "Proved Geq64$" + if i >= 0 { // ERROR "Proved Leq64$" println("x") } } @@ -853,6 +877,149 @@ func unrollIncMin(a []int) int { return x } +// The 4 xxxxExtNto64 functions below test whether prove is looking +// through value-preserving sign/zero extensions of index values (issue #26292). + +// Look through all extensions +func signExtNto64(x []int, j8 int8, j16 int16, j32 int32) int { + if len(x) < 22 { + return 0 + } + if j8 >= 0 && j8 < 22 { + return x[j8] // ERROR "Proved IsInBounds$" + } + if j16 >= 0 && j16 < 22 { + return x[j16] // ERROR "Proved IsInBounds$" + } + if j32 >= 0 && j32 < 22 { + return x[j32] // ERROR "Proved IsInBounds$" + } + return 0 +} + +func zeroExtNto64(x []int, j8 uint8, j16 uint16, j32 uint32) int { + if len(x) < 22 { + return 0 + } + if j8 >= 0 && j8 < 22 { + return x[j8] // ERROR "Proved IsInBounds$" + } + if j16 >= 0 && j16 < 22 { + return x[j16] // ERROR "Proved IsInBounds$" + } + if j32 >= 0 && j32 < 22 { + return x[j32] // ERROR "Proved IsInBounds$" + } + return 0 +} + +// Process fence-post implications through 32to64 extensions (issue #29964) +func signExt32to64Fence(x []int, j int32) int { + if x[j] != 0 { + return 1 + } + if j > 0 && x[j-1] != 0 { // ERROR "Proved IsInBounds$" + return 1 + } + return 0 +} + +func zeroExt32to64Fence(x []int, j uint32) int { + if x[j] != 0 { + return 1 + } + if j > 0 && x[j-1] != 0 { // ERROR "Proved IsInBounds$" + return 1 + } + return 0 +} + +// Ensure that bounds checks with negative indexes are not incorrectly removed. +func negIndex() { + n := make([]int, 1) + for i := -1; i <= 0; i++ { // ERROR "Induction variable: limits \[-1,0\], increment 1$" + n[i] = 1 + } +} +func negIndex2(n int) { + a := make([]int, 5) + b := make([]int, 5) + c := make([]int, 5) + for i := -1; i <= 0; i-- { + b[i] = i + n++ + if n > 10 { + break + } + } + useSlice(a) + useSlice(c) +} + +// Check that prove is zeroing these right shifts of positive ints by bit-width - 1. +// e.g (Rsh64x64 <t> n (Const64 <typ.UInt64> [63])) && ft.isNonNegative(n) -> 0 +func sh64(n int64) int64 { + if n < 0 { + return n + } + return n >> 63 // ERROR "Proved Rsh64x64 shifts to zero" +} + +func sh32(n int32) int32 { + if n < 0 { + return n + } + return n >> 31 // ERROR "Proved Rsh32x64 shifts to zero" +} + +func sh32x64(n int32) int32 { + if n < 0 { + return n + } + return n >> uint64(31) // ERROR "Proved Rsh32x64 shifts to zero" +} + +func sh16(n int16) int16 { + if n < 0 { + return n + } + return n >> 15 // ERROR "Proved Rsh16x64 shifts to zero" +} + +func sh64noopt(n int64) int64 { + return n >> 63 // not optimized; n could be negative +} + +// These cases are division of a positive signed integer by a power of 2. +// The opt pass doesnt have sufficient information to see that n is positive. +// So, instead, opt rewrites the division with a less-than-optimal replacement. +// Prove, which can see that n is nonnegative, cannot see the division because +// opt, an earlier pass, has already replaced it. +// The fix for this issue allows prove to zero a right shift that was added as +// part of the less-than-optimal reqwrite. That change by prove then allows +// lateopt to clean up all the unneccesary parts of the original division +// replacement. See issue #36159. +func divShiftClean(n int) int { + if n < 0 { + return n + } + return n / int(8) // ERROR "Proved Rsh64x64 shifts to zero" +} + +func divShiftClean64(n int64) int64 { + if n < 0 { + return n + } + return n / int64(16) // ERROR "Proved Rsh64x64 shifts to zero" +} + +func divShiftClean32(n int32) int32 { + if n < 0 { + return n + } + return n / int32(16) // ERROR "Proved Rsh32x64 shifts to zero" +} + //go:noinline func useInt(a int) { } diff --git a/test/recover2.go b/test/recover2.go index cf4657a9..31c06ba2 100644 --- a/test/recover2.go +++ b/test/recover2.go @@ -71,7 +71,7 @@ func test5() { } func test6() { - defer mustRecover("unhashable") + defer mustRecover("unhashable type main.T") var x T var z interface{} = x m := make(map[interface{}]int) diff --git a/test/reflectmethod5.go b/test/reflectmethod5.go new file mode 100644 index 00000000..a3fdaa2d --- /dev/null +++ b/test/reflectmethod5.go @@ -0,0 +1,30 @@ +// 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. + +// Issue 38515: failed to mark the method wrapper +// reflect.Type.Method itself as REFLECTMETHOD. + +package main + +import "reflect" + +var called bool + +type foo struct{} + +func (foo) X() { called = true } + +var h = reflect.Type.Method + +func main() { + v := reflect.ValueOf(foo{}) + m := h(v.Type(), 0) + f := m.Func.Interface().(func(foo)) + f(foo{}) + if !called { + panic("FAIL") + } +} diff --git a/test/reflectmethod6.go b/test/reflectmethod6.go new file mode 100644 index 00000000..004ea303 --- /dev/null +++ b/test/reflectmethod6.go @@ -0,0 +1,32 @@ +// 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. + +// Similar to reflectmethod5.go, but for reflect.Type.MethodByName. + +package main + +import "reflect" + +var called bool + +type foo struct{} + +func (foo) X() { called = true } + +var h = reflect.Type.MethodByName + +func main() { + v := reflect.ValueOf(foo{}) + m, ok := h(v.Type(), "X") + if !ok { + panic("FAIL") + } + f := m.Func.Interface().(func(foo)) + f(foo{}) + if !called { + panic("FAIL") + } +} diff --git a/test/rename1.go b/test/rename1.go index 568aa13d..c49a70a2 100644 --- a/test/rename1.go +++ b/test/rename1.go @@ -13,7 +13,7 @@ func main() { var n byte // ERROR "not a type|expected type" var y = float32(0) // ERROR "cannot call|expected function" const ( - a = 1 + iota // ERROR "invalid operation|incompatible types" "cannot convert iota" + a = 1 + iota // ERROR "invalid operation|incompatible types" ) } diff --git a/test/run.go b/test/run.go index 28ed865c..95b94b72 100644 --- a/test/run.go +++ b/test/run.go @@ -34,7 +34,7 @@ var ( keep = flag.Bool("k", false, "keep. keep temporary directory.") numParallel = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run") summary = flag.Bool("summary", false, "show summary of results") - allCodegen = flag.Bool("all_codegen", false, "run all goos/goarch for codegen") + allCodegen = flag.Bool("all_codegen", defaultAllCodeGen(), "run all goos/goarch for codegen") showSkips = flag.Bool("show_skips", false, "show skipped tests") runSkips = flag.Bool("run_skips", false, "run skipped tests (ignore skip and build tags)") linkshared = flag.Bool("linkshared", false, "") @@ -45,6 +45,14 @@ var ( shards = flag.Int("shards", 0, "number of shards. If 0, all tests are run. This is used by the continuous build.") ) +// defaultAllCodeGen returns the default value of the -all_codegen +// flag. By default, we prefer to be fast (returning false), except on +// the linux-amd64 builder that's already very fast, so we get more +// test coverage on trybots. See https://golang.org/issue/34297. +func defaultAllCodeGen() bool { + return os.Getenv("GO_BUILDER_NAME") == "linux-amd64" +} + var ( goos, goarch string @@ -158,14 +166,6 @@ func main() { } } -func toolPath(name string) string { - p := filepath.Join(os.Getenv("GOROOT"), "bin", "tool", name) - if _, err := os.Stat(p); err != nil { - log.Fatalf("didn't find binary at %s", p) - } - return p -} - // goTool reports the path of the go tool to use to run the tests. // If possible, use the same Go used to run run.go, otherwise // fallback to the go version found in the PATH. @@ -193,9 +193,14 @@ func shardMatch(name string) bool { func goFiles(dir string) []string { f, err := os.Open(dir) - check(err) + if err != nil { + log.Fatal(err) + } dirnames, err := f.Readdirnames(-1) - check(err) + f.Close() + if err != nil { + log.Fatal(err) + } names := []string{} for _, name := range dirnames { if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && shardMatch(name) { @@ -253,12 +258,6 @@ type skipError string func (s skipError) Error() string { return string(s) } -func check(err error) { - if err != nil { - log.Fatal(err) - } -} - // test holds the state of a test. type test struct { dir, gofile string @@ -352,7 +351,9 @@ func goDirPackages(longdir string, singlefilepkgs bool) ([][]string, error) { for _, file := range files { name := file.Name() pkgname, err := getPackageNameFromSource(filepath.Join(longdir, name)) - check(err) + if err != nil { + log.Fatal(err) + } i, ok := m[pkgname] if singlefilepkgs || !ok { i = len(pkgs) @@ -458,7 +459,11 @@ func init() { checkShouldTest() } // or else the commands will rebuild any needed packages (like runtime) // over and over. func goGcflags() string { - return "-gcflags=" + os.Getenv("GO_GCFLAGS") + return "-gcflags=all=" + os.Getenv("GO_GCFLAGS") +} + +func goGcflagsIsEmpty() bool { + return "" == os.Getenv("GO_GCFLAGS") } // run runs a test. @@ -491,9 +496,7 @@ func (t *test) run() { // skip first line action = action[nl+1:] } - if strings.HasPrefix(action, "//") { - action = action[2:] - } + action = strings.TrimPrefix(action, "//") // Check for build constraints only up to the actual code. pkgPos := strings.Index(t.src, "\npackage") @@ -592,7 +595,9 @@ func (t *test) run() { } err = ioutil.WriteFile(filepath.Join(t.tempDir, t.gofile), srcBytes, 0644) - check(err) + if err != nil { + log.Fatal(err) + } // A few tests (of things like the environment) require these to be set. if os.Getenv("GOOS") == "" { @@ -602,20 +607,23 @@ func (t *test) run() { os.Setenv("GOARCH", runtime.GOARCH) } - useTmp := true - runInDir := false + var ( + runInDir = t.tempDir + tempDirIsGOPATH = false + ) runcmd := func(args ...string) ([]byte, error) { cmd := exec.Command(args[0], args[1:]...) var buf bytes.Buffer cmd.Stdout = &buf cmd.Stderr = &buf - cmd.Env = os.Environ() - if useTmp { - cmd.Dir = t.tempDir - cmd.Env = envForDir(cmd.Dir) + cmd.Env = append(os.Environ(), "GOENV=off", "GOFLAGS=") + if runInDir != "" { + cmd.Dir = runInDir + // Set PWD to match Dir to speed up os.Getwd in the child process. + cmd.Env = append(cmd.Env, "PWD="+cmd.Dir) } - if runInDir { - cmd.Dir = t.goDirName() + if tempDirIsGOPATH { + cmd.Env = append(cmd.Env, "GOPATH="+t.tempDir) } var err error @@ -666,7 +674,25 @@ func (t *test) run() { } // -S=2 forces outermost line numbers when disassembling inlined code. cmdline := []string{"build", "-gcflags", "-S=2"} - cmdline = append(cmdline, flags...) + + // Append flags, but don't override -gcflags=-S=2; add to it instead. + for i := 0; i < len(flags); i++ { + flag := flags[i] + switch { + case strings.HasPrefix(flag, "-gcflags="): + cmdline[2] += " " + strings.TrimPrefix(flag, "-gcflags=") + case strings.HasPrefix(flag, "--gcflags="): + cmdline[2] += " " + strings.TrimPrefix(flag, "--gcflags=") + case flag == "-gcflags", flag == "--gcflags": + i++ + if i < len(flags) { + cmdline[2] += " " + flags[i] + } + default: + cmdline = append(cmdline, flag) + } + } + cmdline = append(cmdline, long) cmd := exec.Command(goTool(), cmdline...) cmd.Env = append(os.Environ(), env.Environ()...) @@ -805,8 +831,10 @@ func (t *test) run() { pflags = append(pflags, flags...) if setpkgpaths { fp := filepath.Join(longdir, gofiles[0]) - pkgname, serr := getPackageNameFromSource(fp) - check(serr) + pkgname, err := getPackageNameFromSource(fp) + if err != nil { + log.Fatal(err) + } pflags = append(pflags, "-p", pkgname) } _, err := compileInDir(runcmd, longdir, pflags, localImports, gofiles...) @@ -838,13 +866,31 @@ func (t *test) run() { } case "runindir": - // run "go run ." in t.goDirName() - // It's used when test requires go build and run the binary success. - // Example when long import path require (see issue29612.dir) or test - // contains assembly file (see issue15609.dir). - // Verify the expected output. - useTmp = false - runInDir = true + // Make a shallow copy of t.goDirName() in its own module and GOPATH, and + // run "go run ." in it. The module path (and hence import path prefix) of + // the copy is equal to the basename of the source directory. + // + // It's used when test a requires a full 'go build' in order to compile + // the sources, such as when importing multiple packages (issue29612.dir) + // or compiling a package containing assembly files (see issue15609.dir), + // but still needs to be run to verify the expected output. + tempDirIsGOPATH = true + srcDir := t.goDirName() + modName := filepath.Base(srcDir) + gopathSrcDir := filepath.Join(t.tempDir, "src", modName) + runInDir = gopathSrcDir + + if err := overlayDir(gopathSrcDir, srcDir); err != nil { + t.err = err + return + } + + modFile := fmt.Sprintf("module %s\ngo 1.14\n", modName) + if err := ioutil.WriteFile(filepath.Join(gopathSrcDir, "go.mod"), []byte(modFile), 0666); err != nil { + t.err = err + return + } + cmd := []string{goTool(), "run", goGcflags()} if *linkshared { cmd = append(cmd, "-linkshared") @@ -958,13 +1004,13 @@ func (t *test) run() { longdirgofile := filepath.Join(filepath.Join(cwd, t.dir), t.gofile) cmd = append(cmd, flags...) cmd = append(cmd, longdirgofile) - out, err := runcmd(cmd...) + _, err := runcmd(cmd...) if err != nil { t.err = err return } cmd = []string{"./a.exe"} - out, err = runcmd(append(cmd, args...)...) + out, err := runcmd(append(cmd, args...)...) if err != nil { t.err = err return @@ -978,10 +1024,10 @@ func (t *test) run() { // Run Go file if no special go command flags are provided; // otherwise build an executable and run it. // Verify the output. - useTmp = false + runInDir = "" var out []byte var err error - if len(flags)+len(args) == 0 && goGcflags() == "" && !*linkshared { + if len(flags)+len(args) == 0 && goGcflagsIsEmpty() && !*linkshared && goarch == runtime.GOARCH && goos == runtime.GOOS { // If we're not using special go command flags, // skip all the go command machinery. // This avoids any time the go command would @@ -1026,7 +1072,7 @@ func (t *test) run() { defer func() { <-rungatec }() - useTmp = false + runInDir = "" cmd := []string{goTool(), "run", goGcflags()} if *linkshared { cmd = append(cmd, "-linkshared") @@ -1059,7 +1105,7 @@ func (t *test) run() { case "errorcheckoutput": // Run Go file and write its output into temporary Go file. // Compile and errorCheck generated Go file. - useTmp = false + runInDir = "" cmd := []string{goTool(), "run", goGcflags()} if *linkshared { cmd = append(cmd, "-linkshared") @@ -1120,7 +1166,9 @@ func (t *test) String() string { func (t *test) makeTempDir() { var err error t.tempDir, err = ioutil.TempDir("", "") - check(err) + if err != nil { + log.Fatal(err) + } if *keep { log.Printf("Temporary directory is %s", t.tempDir) } @@ -1725,23 +1773,6 @@ func checkShouldTest() { assert(shouldTest("// +build !windows !plan9", "windows", "amd64")) } -// envForDir returns a copy of the environment -// suitable for running in the given directory. -// The environment is the current process's environment -// but with an updated $PWD, so that an os.Getwd in the -// child will be faster. -func envForDir(dir string) []string { - env := os.Environ() - for i, kv := range env { - if strings.HasPrefix(kv, "PWD=") { - env[i] = "PWD=" + dir - return env - } - } - env = append(env, "PWD="+dir) - return env -} - func getenv(key, def string) string { value := os.Getenv(key) if value != "" { @@ -1749,3 +1780,66 @@ func getenv(key, def string) string { } return def } + +// overlayDir makes a minimal-overhead copy of srcRoot in which new files may be added. +func overlayDir(dstRoot, srcRoot string) error { + dstRoot = filepath.Clean(dstRoot) + if err := os.MkdirAll(dstRoot, 0777); err != nil { + return err + } + + srcRoot, err := filepath.Abs(srcRoot) + if err != nil { + return err + } + + return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error { + if err != nil || srcPath == srcRoot { + return err + } + + suffix := strings.TrimPrefix(srcPath, srcRoot) + for len(suffix) > 0 && suffix[0] == filepath.Separator { + suffix = suffix[1:] + } + dstPath := filepath.Join(dstRoot, suffix) + + perm := info.Mode() & os.ModePerm + if info.Mode()&os.ModeSymlink != 0 { + info, err = os.Stat(srcPath) + if err != nil { + return err + } + perm = info.Mode() & os.ModePerm + } + + // Always copy directories (don't symlink them). + // If we add a file in the overlay, we don't want to add it in the original. + if info.IsDir() { + return os.MkdirAll(dstPath, perm|0200) + } + + // If the OS supports symlinks, use them instead of copying bytes. + if err := os.Symlink(srcPath, dstPath); err == nil { + return nil + } + + // Otherwise, copy the bytes. + src, err := os.Open(srcPath) + if err != nil { + return err + } + defer src.Close() + + dst, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) + if err != nil { + return err + } + + _, err = io.Copy(dst, src) + if closeErr := dst.Close(); err == nil { + err = closeErr + } + return err + }) +} diff --git a/test/runtime/inlinegcpc.go b/test/runtime/inlinegcpc.go index 0943205f..c423993b 100644 --- a/test/runtime/inlinegcpc.go +++ b/test/runtime/inlinegcpc.go @@ -1,4 +1,4 @@ -// errorcheck -0 -+ -p=runtime -m -newescape=true +// errorcheck -0 -+ -p=runtime -m // Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/shift1.go b/test/shift1.go index 01ecbed5..df0c032c 100644 --- a/test/shift1.go +++ b/test/shift1.go @@ -18,13 +18,13 @@ func h(x float64) int { return 0 } var ( s uint = 33 u = 1.0 << s // ERROR "invalid operation|shift of non-integer operand" - v float32 = 1 << s // ERROR "invalid" "as type float32" + v float32 = 1 << s // ERROR "invalid" ) // non-constant shift expressions var ( - e1 = g(2.0 << s) // ERROR "invalid|shift of non-integer operand" "as type interface" - f1 = h(2 << s) // ERROR "invalid" "as type float64" + e1 = g(2.0 << s) // ERROR "invalid|shift of non-integer operand" + f1 = h(2 << s) // ERROR "invalid" g1 int64 = 1.1 << s // ERROR "truncated" ) @@ -66,6 +66,7 @@ func _() { u2 = 1<<s != 1.0 // ERROR "non-integer|float64" v float32 = 1 << s // ERROR "non-integer|float32" w int64 = 1.0 << 33 // 1.0<<33 is a constant shift expression + _, _, _, _, _, _, _, _, _, _ = j, k, m, n, o, u, u1, u2, v, w ) diff --git a/test/sinit_run.go b/test/sinit_run.go index fdd19c49..c37fc9b8 100644 --- a/test/sinit_run.go +++ b/test/sinit_run.go @@ -12,20 +12,32 @@ package main import ( "bytes" "fmt" + "io/ioutil" "os" "os/exec" ) func main() { - cmd := exec.Command("go", "tool", "compile", "-S", "sinit.go") + f, err := ioutil.TempFile("", "sinit-*.o") + if err != nil { + fmt.Println(err) + os.Exit(1) + } + f.Close() + + cmd := exec.Command("go", "tool", "compile", "-o", f.Name(), "-S", "sinit.go") out, err := cmd.CombinedOutput() + os.Remove(f.Name()) if err != nil { fmt.Println(string(out)) fmt.Println(err) os.Exit(1) } - os.Remove("sinit.o") + if len(bytes.TrimSpace(out)) == 0 { + fmt.Println("'go tool compile -S sinit.go' printed no output") + os.Exit(1) + } if bytes.Contains(out, []byte("initdone")) { fmt.Println("sinit generated an init function") os.Exit(1) diff --git a/test/strength.go b/test/strength.go index 94d589c2..823d05af 100644 --- a/test/strength.go +++ b/test/strength.go @@ -5,7 +5,7 @@ // license that can be found in the LICENSE file. // Generate test of strength reduction for multiplications -// with contstants. Especially useful for amd64/386. +// with constants. Especially useful for amd64/386. package main diff --git a/test/syntax/chan1.go b/test/syntax/chan1.go index 4eb63796..56103d1d 100644 --- a/test/syntax/chan1.go +++ b/test/syntax/chan1.go @@ -10,7 +10,7 @@ var c chan int var v int func main() { - if c <- v { // ERROR "used as value" + if c <- v { // ERROR "cannot use c <- v as value" } } diff --git a/test/syntax/typesw.go b/test/syntax/typesw.go index f9120e88..37819339 100644 --- a/test/syntax/typesw.go +++ b/test/syntax/typesw.go @@ -7,7 +7,7 @@ package main func main() { - switch main() := interface{}(nil).(type) { // ERROR "invalid variable name|used as value" + switch main() := interface{}(nil).(type) { // ERROR "invalid variable name|cannot use .* as value" default: } } diff --git a/test/typecheck.go b/test/typecheck.go index 6f120428..4c55d2ed 100644 --- a/test/typecheck.go +++ b/test/typecheck.go @@ -1,5 +1,9 @@ // errorcheck +// Copyright 2012 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. + // Verify that the Go compiler will not // die after running into an undefined // type in the argument list for a @@ -8,11 +12,11 @@ package main -func mine(int b) int { // ERROR "undefined.*b" - return b + 2 // ERROR "undefined.*b" +func mine(int b) int { // ERROR "undefined.*b" + return b + 2 // ERROR "undefined.*b" } func main() { - mine() // GCCGO_ERROR "not enough arguments" - c = mine() // ERROR "undefined.*c|not enough arguments" + mine() // GCCGO_ERROR "not enough arguments" + c = mine() // ERROR "undefined.*c|not enough arguments" } diff --git a/test/typeswitch2.go b/test/typeswitch2.go index 5958b7db..62c96c83 100644 --- a/test/typeswitch2.go +++ b/test/typeswitch2.go @@ -35,13 +35,3 @@ func whatis(x interface{}) string { } return "" } - -func notused(x interface{}) { - // The first t is in a different scope than the 2nd t; it cannot - // be accessed (=> declared and not used error); but it is legal - // to declare it. - switch t := 0; t := x.(type) { // ERROR "declared and not used" - case int: - _ = t // this is using the t of "t := x.(type)" - } -} diff --git a/test/typeswitch2b.go b/test/typeswitch2b.go new file mode 100644 index 00000000..6da0d5fa --- /dev/null +++ b/test/typeswitch2b.go @@ -0,0 +1,20 @@ +// errorcheck + +// 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. + +// Verify that various erroneous type switches are caught by the compiler. +// Does not compile. + +package main + +func notused(x interface{}) { + // The first t is in a different scope than the 2nd t; it cannot + // be accessed (=> declared but not used error); but it is legal + // to declare it. + switch t := 0; t := x.(type) { // ERROR "declared but not used" + case int: + _ = t // this is using the t of "t := x.(type)" + } +} diff --git a/test/uintptrescapes2.go b/test/uintptrescapes2.go index b8117b85..3ff1d940 100644 --- a/test/uintptrescapes2.go +++ b/test/uintptrescapes2.go @@ -1,4 +1,4 @@ -// errorcheck -0 -m -live +// errorcheck -0 -l -m -live // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -13,31 +13,53 @@ import ( ) //go:uintptrescapes -//go:noinline func F1(a uintptr) {} // ERROR "escaping uintptr" //go:uintptrescapes -//go:noinline -func F2(a ...uintptr) {} // ERROR "escaping ...uintptr" "a does not escape" +func F2(a ...uintptr) {} // ERROR "escaping ...uintptr" //go:uintptrescapes -//go:noinline func F3(uintptr) {} // ERROR "escaping uintptr" //go:uintptrescapes -//go:noinline func F4(...uintptr) {} // ERROR "escaping ...uintptr" -func G() { +type T struct{} + +//go:uintptrescapes +func (T) M1(a uintptr) {} // ERROR "escaping uintptr" + +//go:uintptrescapes +func (T) M2(a ...uintptr) {} // ERROR "escaping ...uintptr" "leaking param: a" + +func TestF1() { var t int // ERROR "moved to heap" F1(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to F1: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$" +} + +func TestF3() { var t2 int // ERROR "moved to heap" - F3(uintptr(unsafe.Pointer(&t2))) // ERROR "live at call to F3: .?autotmp" + F3(uintptr(unsafe.Pointer(&t2))) // ERROR "live at call to F3: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$" } -func H() { +func TestM1() { + var t T + var v int // ERROR "moved to heap" + t.M1(uintptr(unsafe.Pointer(&v))) // ERROR "live at call to T.M1: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$" +} + +func TestF2() { var v int // ERROR "moved to heap" F2(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F2: .?autotmp" "escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$" +} + +func TestF4() { var v2 int // ERROR "moved to heap" - F4(0, 1, uintptr(unsafe.Pointer(&v2)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F4: .?autotmp" "escapes to heap" + F4(0, 1, uintptr(unsafe.Pointer(&v2)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F4: .?autotmp" "escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$" +} + +func TestM2() { + var t T + var v int // ERROR "moved to heap" + t.M2(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to T.M2: .?autotmp" "escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$" } diff --git a/test/uintptrescapes3.go b/test/uintptrescapes3.go new file mode 100644 index 00000000..92be5d1e --- /dev/null +++ b/test/uintptrescapes3.go @@ -0,0 +1,63 @@ +// run + +// 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. + +// Test that //go:uintptrescapes works for methods. + +package main + +import ( + "fmt" + "runtime" + "unsafe" +) + +var callback func() + +//go:noinline +//go:uintptrescapes +func F(ptr uintptr) { callback() } + +//go:noinline +//go:uintptrescapes +func Fv(ptrs ...uintptr) { callback() } + +type T struct{} + +//go:noinline +//go:uintptrescapes +func (T) M(ptr uintptr) { callback() } + +//go:noinline +//go:uintptrescapes +func (T) Mv(ptrs ...uintptr) { callback() } + +// Each test should pass uintptr(ptr) as an argument to a function call, +// which in turn should call callback. The callback checks that ptr is kept alive. +var tests = []func(ptr unsafe.Pointer){ + func(ptr unsafe.Pointer) { F(uintptr(ptr)) }, + func(ptr unsafe.Pointer) { Fv(uintptr(ptr)) }, + func(ptr unsafe.Pointer) { T{}.M(uintptr(ptr)) }, + func(ptr unsafe.Pointer) { T{}.Mv(uintptr(ptr)) }, +} + +func main() { + for i, test := range tests { + finalized := false + + ptr := new([64]byte) + runtime.SetFinalizer(ptr, func(*[64]byte) { + finalized = true + }) + + callback = func() { + runtime.GC() + if finalized { + fmt.Printf("test #%d failed\n", i) + } + } + test(unsafe.Pointer(ptr)) + } +} diff --git a/test/winbatch.go b/test/winbatch.go new file mode 100644 index 00000000..c3b48d38 --- /dev/null +++ b/test/winbatch.go @@ -0,0 +1,68 @@ +// 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. + +// Check that batch files are maintained as CRLF files (consistent +// behavior on all operating systems). See golang.org/issue/37791. + +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "runtime" + "strings" +) + +func main() { + // Ensure that the GOROOT/src/all.bat file exists and has strict CRLF line endings. + enforceBatchStrictCRLF(filepath.Join(runtime.GOROOT(), "src", "all.bat")) + + // Walk the entire Go repository source tree (without GOROOT/pkg), + // skipping directories that start with "." and named "testdata", + // and ensure all .bat files found have exact CRLF line endings. + err := filepath.Walk(runtime.GOROOT(), func(path string, fi os.FileInfo, err error) error { + if err != nil { + return err + } + if fi.IsDir() && (strings.HasPrefix(fi.Name(), ".") || fi.Name() == "testdata") { + return filepath.SkipDir + } + if path == filepath.Join(runtime.GOROOT(), "pkg") { + // GOROOT/pkg is known to contain generated artifacts, not source code. + // Skip it to avoid false positives. (Also see golang.org/issue/37929.) + return filepath.SkipDir + } + if filepath.Ext(fi.Name()) == ".bat" { + enforceBatchStrictCRLF(path) + } + return nil + }) + if err != nil { + log.Fatalln(err) + } +} + +func enforceBatchStrictCRLF(path string) { + b, err := ioutil.ReadFile(path) + if err != nil { + log.Fatalln(err) + } + cr, lf := bytes.Count(b, []byte{13}), bytes.Count(b, []byte{10}) + crlf := bytes.Count(b, []byte{13, 10}) + if cr != crlf || lf != crlf { + if rel, err := filepath.Rel(runtime.GOROOT(), path); err == nil { + // Make the test failure more readable by showing a path relative to GOROOT. + path = rel + } + fmt.Printf("Windows batch file %s does not use strict CRLF line termination.\n", path) + fmt.Printf("Please convert it to CRLF before checking it in due to golang.org/issue/37791.\n") + os.Exit(1) + } +} diff --git a/test/writebarrier.go b/test/writebarrier.go index 8cd559c1..dbf0b6dd 100644 --- a/test/writebarrier.go +++ b/test/writebarrier.go @@ -148,12 +148,12 @@ func f16(x []T8, y T8) []T8 { func t1(i interface{}) **int { // From issue 14306, make sure we have write barriers in a type switch // where the assigned variable escapes. - switch x := i.(type) { // ERROR "write barrier" - case *int: + switch x := i.(type) { + case *int: // ERROR "write barrier" return &x } - switch y := i.(type) { // no write barrier here - case **int: + switch y := i.(type) { + case **int: // no write barrier here return y } return nil |