cmd/compile: fix bogus "fallthrough statement out of place"

When processing a fallthrough, the casebody function in swt.go
checks that the last statement has indeed Op == OXFALL (not-processed
fallthrough) before setting it to OFALL (processed fallthrough).

Unfortunately, sometimes the fallthrough statement won't be in the
last node. For example, in

case 0:
	 return func() int {return 1}()
	 fallthrough

the compiler generates

autotmp_0 = (func literal)(); return autotmp_0; fallthrough; <node VARKILL>

with an OVARKILL node in the last position. casebody will find that
last.Op != OXFALL, won't mark the fallthrough as processed, and the
fallthrough line will cause a "fallthrough statement out of place" error.

To fix this, we change casebody so that it searches for the fallthrough
statement backwards in the statements list, without assuming that it'll
be in the last position.

Fixes #13262

Change-Id: I366c6caa7fd7442d365bd7a08cc66a552212d9b2
Reviewed-on: https://go-review.googlesource.com/22921
Run-TryBot: Quentin Smith <quentin@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Quentin Smith <quentin@golang.org>
This commit is contained in:
Alberto Donizetti 2016-05-07 21:34:04 +02:00 committed by Quentin Smith
parent d15295c679
commit 375092bdcb
3 changed files with 33 additions and 2 deletions

View file

@ -449,8 +449,18 @@ func casebody(sw *Node, typeswvar *Node) {
}
stat = append(stat, n.Nbody.Slice()...)
// Search backwards for the index of the fallthrough
// statement. Do not assume it'll be in the last
// position, since in some cases (e.g. when the statement
// list contains autotmp_ variables), one or more OVARKILL
// nodes will be at the end of the list.
fallIndex := len(stat) - 1
for stat[fallIndex].Op == OVARKILL {
fallIndex--
}
last := stat[fallIndex]
// botch - shouldn't fall through declaration
last := stat[len(stat)-1]
if last.Xoffset == n.Xoffset && last.Op == OXFALL {
if typeswvar != nil {
setlineno(last)

View file

@ -195,7 +195,7 @@ func walkstmt(n *Node) *Node {
n.Op = OEMPTY // don't leave plain values as statements.
}
// special case for a receive where we throw away
// special case for a receive where we throw away
// the value received.
case ORECV:
if n.Typecheck == 0 {

View file

@ -0,0 +1,21 @@
// compile
// 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.
// Issue 13262: cmd/compile: bogus "fallthrough
// statement out of place" error
package p
func f() int {
var a int
switch a {
case 0:
return func() int { return 1 }()
fallthrough
default:
}
return 0
}