go/ssa: handle labeled statements with blank labels
A labeled statement with a blank label can't be the target of a goto,
break, or continue statement, so we don't need to create a new block for
it in builder.stmt.
Function.labelledBlock, which previously would be called to get a new
block, panics for blank labels anyway, because the type-checker doesn't
associate a blank label's *ast.Ident with a *types.Object.
Change-Id: I5f67214c0c35c6c2daf666dc2bd6d0169617e4ee
Reviewed-on: https://go-review.googlesource.com/c/tools/+/568675
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Tim King <taking@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Tim King <taking@google.com>
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
diff --git a/go/ssa/builder.go b/go/ssa/builder.go
index b991e29..267fd42 100644
--- a/go/ssa/builder.go
+++ b/go/ssa/builder.go
@@ -2338,6 +2338,12 @@
}
case *ast.LabeledStmt:
+ if s.Label.Name == "_" {
+ // Blank labels can't be the target of a goto, break,
+ // or continue statement, so we don't need a new block.
+ _s = s.Stmt
+ goto start
+ }
label = fn.labelledBlock(s.Label)
emitJump(fn, label._goto)
fn.currentBlock = label._goto
diff --git a/go/ssa/builder_test.go b/go/ssa/builder_test.go
index 829ddc7..607e64f 100644
--- a/go/ssa/builder_test.go
+++ b/go/ssa/builder_test.go
@@ -1210,3 +1210,30 @@
})
}
}
+
+// TestLabels just tests that anonymous labels are handled.
+func TestLabels(t *testing.T) {
+ tests := []string{
+ `package main
+ func main() { _:println(1) }`,
+ `package main
+ func main() { _:println(1); _:println(2)}`,
+ }
+ for _, test := range tests {
+ conf := loader.Config{Fset: token.NewFileSet()}
+ f, err := parser.ParseFile(conf.Fset, "<input>", test, 0)
+ if err != nil {
+ t.Errorf("parse error: %s", err)
+ return
+ }
+ conf.CreateFromFiles("main", f)
+ iprog, err := conf.Load()
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ prog := ssautil.CreateProgram(iprog, ssa.BuilderMode(0))
+ pkg := prog.Package(iprog.Created[0].Pkg)
+ pkg.Build()
+ }
+}
diff --git a/go/ssa/func.go b/go/ssa/func.go
index 4d3e391..d4a21c7 100644
--- a/go/ssa/func.go
+++ b/go/ssa/func.go
@@ -106,6 +106,7 @@
// labelledBlock returns the branch target associated with the
// specified label, creating it if needed.
+// label should be a non-blank identifier (label.Name != "_").
func (f *Function) labelledBlock(label *ast.Ident) *lblock {
obj := f.objectOf(label).(*types.Label)
lb := f.lblocks[obj]