mirror of
https://github.com/golang/go
synced 2024-09-05 07:54:46 +00:00
test: add -update_errors flag to run script
The flag updates error annotations in test files from actual compiler output. This is useful when doing compiler changes that add/remove/change lots of errors, or when adding lots of new tests. Also I noticed at least 2 cases where annotation were sub-optimal: 1. The annotation was "leaking param p" when the actual error is "leaking param p to result ~r1". 2. The annotation was "leaking param m" when the actual errors are "leaking param m" and "leaking param mv1". For now it works only for errorcheck mode. Also, apply the update to escape and liveness tests. Some files have gccgo-specific errors of the form "gc error|gccgo error", so it is risky to run update on all files. Gccgo-specific error does not necessary contain '|', it can be just truncated. Change-Id: Iaaae767f859dcb8321a8cb4970b2b70969e8a345 Reviewed-on: https://go-review.googlesource.com/5310 Run-TryBot: Dmitry Vyukov <dvyukov@google.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
a5dec3859a
commit
7647741246
874
test/escape2.go
874
test/escape2.go
File diff suppressed because it is too large
Load diff
874
test/escape2n.go
874
test/escape2n.go
File diff suppressed because it is too large
Load diff
78
test/live.go
78
test/live.go
|
@ -64,7 +64,7 @@ func f3(b bool) {
|
|||
printpointer(&y) // ERROR "live at call to printpointer: x y$"
|
||||
printpointer(&y) // ERROR "live at call to printpointer: x y$"
|
||||
}
|
||||
printint(0) // ERROR "live at call to printint: x y$" "x \(type \*int\) is ambiguously live" "y \(type \*int\) is ambiguously live"
|
||||
printint(0) // ERROR "f3: x \(type \*int\) is ambiguously live$" "f3: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
|
||||
}
|
||||
|
||||
// The old algorithm treated x as live on all code that
|
||||
|
@ -103,7 +103,7 @@ func f5(b1 bool) {
|
|||
*y = 54
|
||||
z = &y
|
||||
}
|
||||
printint(**z) // ERROR "live at call to printint: x y$" "x \(type \*int\) is ambiguously live" "y \(type \*int\) is ambiguously live"
|
||||
printint(**z) // ERROR "f5: x \(type \*int\) is ambiguously live$" "f5: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
|
||||
}
|
||||
|
||||
// confusion about the _ result used to cause spurious "live at entry to f6: _".
|
||||
|
@ -137,7 +137,7 @@ var i9 interface{}
|
|||
func f9() bool {
|
||||
g8()
|
||||
x := i9
|
||||
return x != interface{}(99.0i) // ERROR "live at call to convT2E: x"
|
||||
return x != interface{}(99.0i) // ERROR "live at call to convT2E: x$"
|
||||
}
|
||||
|
||||
// liveness formerly confused by UNDEF followed by RET,
|
||||
|
@ -157,10 +157,10 @@ var b bool
|
|||
|
||||
// this used to have a spurious "live at entry to f11a: ~r0"
|
||||
func f11a() *int {
|
||||
select { // ERROR "live at call to newselect: autotmp" "live at call to selectgo: autotmp"
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp"
|
||||
select { // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
|
||||
return nil
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp"
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -172,10 +172,10 @@ func f11b() *int {
|
|||
// get to the bottom of the function.
|
||||
// This used to have a spurious "live at call to printint: p".
|
||||
printint(1) // nothing live here!
|
||||
select { // ERROR "live at call to newselect: autotmp" "live at call to selectgo: autotmp"
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp"
|
||||
select { // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
|
||||
return nil
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp"
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -188,10 +188,10 @@ func f11c() *int {
|
|||
if b {
|
||||
// Unlike previous, the cases in this select fall through,
|
||||
// so we can get to the println, so p is not dead.
|
||||
printint(1) // ERROR "live at call to printint: p"
|
||||
select { // ERROR "live at call to newselect: autotmp.* p" "live at call to selectgo: autotmp.* p"
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp.* p"
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp.* p"
|
||||
printint(1) // ERROR "live at call to printint: p$"
|
||||
select { // ERROR "live at call to newselect: autotmp_[0-9]+ p$" "live at call to selectgo: autotmp_[0-9]+ p$"
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
|
||||
case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
|
||||
}
|
||||
}
|
||||
println(*p)
|
||||
|
@ -215,7 +215,7 @@ func f12() *int {
|
|||
|
||||
func f13() {
|
||||
s := "hello"
|
||||
s = h13(s, g13(s)) // ERROR "live at call to g13: s"
|
||||
s = h13(s, g13(s)) // ERROR "live at call to g13: s$"
|
||||
}
|
||||
|
||||
func g13(string) string
|
||||
|
@ -225,7 +225,7 @@ func h13(string, string) string
|
|||
|
||||
func f14() {
|
||||
x := g14()
|
||||
printstringpointer(&x) // ERROR "live at call to printstringpointer: x"
|
||||
printstringpointer(&x) // ERROR "live at call to printstringpointer: x$"
|
||||
}
|
||||
|
||||
func g14() string
|
||||
|
@ -233,8 +233,8 @@ func g14() string
|
|||
func f15() {
|
||||
var x string
|
||||
_ = &x
|
||||
x = g15() // ERROR "live at call to g15: x"
|
||||
printstring(x) // ERROR "live at call to printstring: x"
|
||||
x = g15() // ERROR "live at call to g15: x$"
|
||||
printstring(x) // ERROR "live at call to printstring: x$"
|
||||
}
|
||||
|
||||
func g15() string
|
||||
|
@ -367,9 +367,9 @@ func f25(b bool) {
|
|||
}
|
||||
var x string
|
||||
_ = &x
|
||||
x = g15() // ERROR "live at call to g15: x"
|
||||
printstring(x) // ERROR "live at call to printstring: x"
|
||||
} // ERROR "live at call to deferreturn: x"
|
||||
x = g15() // ERROR "live at call to g15: x$"
|
||||
printstring(x) // ERROR "live at call to printstring: x$"
|
||||
} // ERROR "live at call to deferreturn: x$"
|
||||
|
||||
func g25()
|
||||
|
||||
|
@ -408,7 +408,7 @@ func f27defer(b bool) {
|
|||
if b {
|
||||
defer call27(func() { x++ }) // ERROR "live at call to deferproc: autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+$"
|
||||
}
|
||||
defer call27(func() { x++ }) // ERROR "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$" "ambiguously live"
|
||||
defer call27(func() { x++ }) // ERROR "f27defer: autotmp_[0-9]+ \(type struct { F uintptr; x \*int }\) is ambiguously live$" "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
|
||||
printnl() // ERROR "live at call to printnl: autotmp_[0-9]+ autotmp_[0-9]+$"
|
||||
} // ERROR "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
|
||||
|
||||
|
@ -417,9 +417,9 @@ func f27defer(b bool) {
|
|||
func f27go(b bool) {
|
||||
x := 0
|
||||
if b {
|
||||
go call27(func() { x++ }) // ERROR "live at call to newobject: &x" "live at call to newproc: &x$"
|
||||
go call27(func() { x++ }) // ERROR "live at call to newobject: &x$" "live at call to newproc: &x$"
|
||||
}
|
||||
go call27(func() { x++ }) // ERROR "live at call to newobject: &x"
|
||||
go call27(func() { x++ }) // ERROR "live at call to newobject: &x$"
|
||||
printnl()
|
||||
}
|
||||
|
||||
|
@ -481,7 +481,7 @@ func f31(b1, b2, b3 bool) {
|
|||
g31("a") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to g31: autotmp_[0-9]+$"
|
||||
}
|
||||
if b2 {
|
||||
h31("b") // ERROR "live at call to newobject: autotmp_[0-9]+$" "live at call to convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$"
|
||||
h31("b") // ERROR "live at call to convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$" "live at call to newobject: autotmp_[0-9]+$"
|
||||
}
|
||||
if b3 {
|
||||
panic("asdf") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to gopanic: autotmp_[0-9]+$"
|
||||
|
@ -496,7 +496,7 @@ func h31(...interface{})
|
|||
|
||||
type T32 int
|
||||
|
||||
func (t *T32) Inc() { // ERROR "live at entry"
|
||||
func (t *T32) Inc() { // ERROR "live at entry to \(\*T32\).Inc: t$"
|
||||
*t++
|
||||
}
|
||||
|
||||
|
@ -573,14 +573,14 @@ func f38(b bool) {
|
|||
// we care that the println lines have no live variables
|
||||
// and therefore no output.
|
||||
if b {
|
||||
select { // ERROR "live at call"
|
||||
case <-fc38(): // ERROR "live at call"
|
||||
select { // ERROR "live at call to newselect: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
|
||||
case <-fc38(): // ERROR "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
|
||||
printnl()
|
||||
case fc38() <- *fi38(1): // ERROR "live at call"
|
||||
case fc38() <- *fi38(1): // ERROR "live at call to fc38: autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectsend: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
|
||||
printnl()
|
||||
case *fi38(2) = <-fc38(): // ERROR "live at call"
|
||||
case *fi38(2) = <-fc38(): // ERROR "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
|
||||
printnl()
|
||||
case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call"
|
||||
case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call to fb38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv2: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
|
||||
printnl()
|
||||
}
|
||||
printnl()
|
||||
|
@ -592,27 +592,27 @@ func f38(b bool) {
|
|||
|
||||
func f39() (x []int) {
|
||||
x = []int{1}
|
||||
printnl() // ERROR "live at call to printnl: x"
|
||||
printnl() // ERROR "live at call to printnl: x$"
|
||||
return x
|
||||
}
|
||||
|
||||
func f39a() (x []int) {
|
||||
x = []int{1}
|
||||
printnl() // ERROR "live at call to printnl: x"
|
||||
printnl() // ERROR "live at call to printnl: x$"
|
||||
return
|
||||
}
|
||||
|
||||
func f39b() (x [10]*int) {
|
||||
x = [10]*int{}
|
||||
x[0] = new(int) // ERROR "live at call to newobject: x"
|
||||
printnl() // ERROR "live at call to printnl: x"
|
||||
x[0] = new(int) // ERROR "live at call to newobject: x$"
|
||||
printnl() // ERROR "live at call to printnl: x$"
|
||||
return x
|
||||
}
|
||||
|
||||
func f39c() (x [10]*int) {
|
||||
x = [10]*int{}
|
||||
x[0] = new(int) // ERROR "live at call to newobject: x"
|
||||
printnl() // ERROR "live at call to printnl: x"
|
||||
x[0] = new(int) // ERROR "live at call to newobject: x$"
|
||||
printnl() // ERROR "live at call to printnl: x$"
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -625,7 +625,7 @@ type T40 struct {
|
|||
|
||||
func newT40() *T40 {
|
||||
ret := T40{}
|
||||
ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret"
|
||||
ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret$"
|
||||
return &ret
|
||||
}
|
||||
|
||||
|
@ -637,8 +637,8 @@ func bad40() {
|
|||
|
||||
func good40() {
|
||||
ret := T40{}
|
||||
ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_.* ret"
|
||||
ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_[0-9]+ ret$"
|
||||
t := &ret
|
||||
printnl() // ERROR "live at call to printnl: autotmp_.* ret"
|
||||
printnl() // ERROR "live at call to printnl: autotmp_[0-9]+ ret$"
|
||||
_ = t
|
||||
}
|
||||
|
|
107
test/run.go
107
test/run.go
|
@ -36,6 +36,7 @@ var (
|
|||
numParallel = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run")
|
||||
summary = flag.Bool("summary", false, "show summary of results")
|
||||
showSkips = flag.Bool("show_skips", false, "show skipped tests")
|
||||
updateErrors = flag.Bool("update_errors", false, "update error messages in test file based on compiler output")
|
||||
runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run")
|
||||
)
|
||||
|
||||
|
@ -521,6 +522,9 @@ func (t *test) run() {
|
|||
return
|
||||
}
|
||||
}
|
||||
if *updateErrors {
|
||||
t.updateErrors(string(out), long)
|
||||
}
|
||||
t.err = t.errorCheck(string(out), long, t.gofile)
|
||||
return
|
||||
|
||||
|
@ -721,6 +725,25 @@ func (t *test) expectedOutput() string {
|
|||
return string(b)
|
||||
}
|
||||
|
||||
func splitOutput(out string) []string {
|
||||
// 6g error messages continue onto additional lines with leading tabs.
|
||||
// Split the output at the beginning of each line that doesn't begin with a tab.
|
||||
var res []string
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
if strings.HasSuffix(line, "\r") { // remove '\r', output by compiler on windows
|
||||
line = line[:len(line)-1]
|
||||
}
|
||||
if strings.HasPrefix(line, "\t") {
|
||||
res[len(res)-1] += "\n" + line
|
||||
} else if strings.HasPrefix(line, "go tool") {
|
||||
continue
|
||||
} else if strings.TrimSpace(line) != "" {
|
||||
res = append(res, line)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
|
||||
defer func() {
|
||||
if *verbose && err != nil {
|
||||
|
@ -728,22 +751,7 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
|
|||
}
|
||||
}()
|
||||
var errs []error
|
||||
|
||||
var out []string
|
||||
// 6g error messages continue onto additional lines with leading tabs.
|
||||
// Split the output at the beginning of each line that doesn't begin with a tab.
|
||||
for _, line := range strings.Split(outStr, "\n") {
|
||||
if strings.HasSuffix(line, "\r") { // remove '\r', output by compiler on windows
|
||||
line = line[:len(line)-1]
|
||||
}
|
||||
if strings.HasPrefix(line, "\t") {
|
||||
out[len(out)-1] += "\n" + line
|
||||
} else if strings.HasPrefix(line, "go tool") {
|
||||
continue
|
||||
} else if strings.TrimSpace(line) != "" {
|
||||
out = append(out, line)
|
||||
}
|
||||
}
|
||||
out := splitOutput(outStr)
|
||||
|
||||
// Cut directory name.
|
||||
for i := range out {
|
||||
|
@ -800,7 +808,72 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
|
|||
fmt.Fprintf(&buf, "%s\n", err.Error())
|
||||
}
|
||||
return errors.New(buf.String())
|
||||
}
|
||||
|
||||
func (t *test) updateErrors(out string, file string) {
|
||||
// Read in source file.
|
||||
src, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return
|
||||
}
|
||||
lines := strings.Split(string(src), "\n")
|
||||
// Remove old errors.
|
||||
for i, ln := range lines {
|
||||
pos := strings.Index(ln, " // ERROR ")
|
||||
if pos >= 0 {
|
||||
lines[i] = ln[:pos]
|
||||
}
|
||||
}
|
||||
// Parse new errors.
|
||||
errors := make(map[int]map[string]bool)
|
||||
tmpRe := regexp.MustCompile(`autotmp_[0-9]+`)
|
||||
for _, errStr := range splitOutput(out) {
|
||||
colon1 := strings.Index(errStr, ":")
|
||||
if colon1 < 0 || errStr[:colon1] != file{
|
||||
continue
|
||||
}
|
||||
colon2 := strings.Index(errStr[colon1+1:], ":")
|
||||
if colon2 < 0 {
|
||||
continue
|
||||
}
|
||||
colon2 += colon1+1
|
||||
line, err := strconv.Atoi(errStr[colon1+1:colon2])
|
||||
line--
|
||||
if err != nil || line < 0 || line >= len(lines) {
|
||||
continue
|
||||
}
|
||||
msg := errStr[colon2+2:]
|
||||
for _, r := range []string{`\`, `*`, `+`, `[`, `]`, `(`, `)`} {
|
||||
msg = strings.Replace(msg, r, `\` + r, -1)
|
||||
}
|
||||
msg = strings.Replace(msg, `"`, `.`, -1)
|
||||
msg = tmpRe.ReplaceAllLiteralString(msg, `autotmp_[0-9]+`)
|
||||
if errors[line] == nil {
|
||||
errors[line] = make(map[string]bool)
|
||||
}
|
||||
errors[line][msg] = true
|
||||
}
|
||||
// Add new errors.
|
||||
for line, errs := range errors {
|
||||
var sorted []string
|
||||
for e := range errs {
|
||||
sorted = append(sorted, e)
|
||||
}
|
||||
sort.Strings(sorted)
|
||||
lines[line] += " // ERROR"
|
||||
for _, e := range sorted {
|
||||
lines[line] += fmt.Sprintf(` "%s$"`, e)
|
||||
}
|
||||
}
|
||||
// Write new file.
|
||||
err = ioutil.WriteFile(file, []byte(strings.Join(lines, "\n")), 0640)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return
|
||||
}
|
||||
// Polish.
|
||||
exec.Command("go", "fmt", file).CombinedOutput()
|
||||
}
|
||||
|
||||
// matchPrefix reports whether s is of the form ^(.*/)?prefix(:|[),
|
||||
|
@ -884,7 +957,7 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) {
|
|||
var err error
|
||||
re, err = regexp.Compile(rx)
|
||||
if err != nil {
|
||||
log.Fatalf("%s:%d: invalid regexp in ERROR line: %v", t.goFileName(), lineNum, err)
|
||||
log.Fatalf("%s:%d: invalid regexp \"%s\" in ERROR line: %v", t.goFileName(), lineNum, rx, err)
|
||||
}
|
||||
cache[rx] = re
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue