Skip to content

Commit

Permalink
cmd/compile: modify swt.go to skip repeated walks of switch
Browse files Browse the repository at this point in the history
The compiler appears to contain several squirrelly corner
cases where nodes are double walked, some where new nodes
are created from walked parts.  Rather than trust that we
had searched hard enough for the last one, change
exprSwitch.walk() to return immediately if it has already
been walked.  This appears to be the only case where
double-walking a node is actually harmful.

Fixes #29562.

Change-Id: I0667e8769aba4c3236666cd836a934e256c0bfc5
Reviewed-on: https://go-review.googlesource.com/c/156317
Run-TryBot: David Chase <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Keith Randall <[email protected]>
  • Loading branch information
dr2chase committed Jan 4, 2019
1 parent 86e31bc commit 28fb8c6
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/cmd/compile/internal/gc/swt.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ func walkswitch(sw *Node) {
func (s *exprSwitch) walk(sw *Node) {
// Guard against double walk, see #25776.
if sw.List.Len() == 0 && sw.Nbody.Len() > 0 {
Fatalf("second walk of switch")
return // Was fatal, but eliminating every possible source of double-walking is hard
}

casebody(sw, nil)
Expand Down Expand Up @@ -302,7 +302,7 @@ func (s *exprSwitch) walk(sw *Node) {
s.exprname = cond
} else {
s.exprname = temp(cond.Type)
cas = []*Node{nod(OAS, s.exprname, cond)}
cas = []*Node{nod(OAS, s.exprname, cond)} // This gets walk()ed again in walkstmtlist just before end of this function. See #29562.
typecheckslice(cas, ctxStmt)
}

Expand Down
26 changes: 26 additions & 0 deletions test/fixedbugs/issue29562.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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.

// Triggers a double walk of the (inlined) switch in il

package p

func il(s string) string {
switch len(s) {
case 0:
return "zero"
case 1:
return "one"
}
return s
}

func f() {
var s string
var as []string
switch false && (s+"a"+as[0]+il(s)+as[0]+s == "") {
}
}

0 comments on commit 28fb8c6

Please sign in to comment.