From 68e390304e94ef6c86f875c6a5e4514f7d5ba50f Mon Sep 17 00:00:00 2001 From: griesemer Date: Tue, 10 Oct 2017 16:56:56 -0700 Subject: [PATCH] cmd/compile/internal/syntax: consider function nesting for error recovery This re-enables functionality that inadvertently was disabled in the (long) past. Also, don't perform branch checks if we had errors in a function to avoid spurious errors or (worst-case) crashes. Slightly modified test/fixedbugs/issue14006.go to make sure the test still reports invalid label errors (the surrounding function must be syntactically correct). Change-Id: Id5642930877d7cf3400649094ec75c753b5084b7 Reviewed-on: https://go-review.googlesource.com/69770 Run-TryBot: Robert Griesemer Reviewed-by: Matthew Dempsky TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/syntax/parser.go | 21 ++++++++++++--------- test/fixedbugs/issue14006.go | 3 +++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index c04322890c..b77356a7e5 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -23,6 +23,7 @@ type parser struct { scanner first error // first error encountered + errcnt int // number of errors encountered pragma Pragma // pragma flags fnest int // function nesting level (for error handling) @@ -57,6 +58,7 @@ func (p *parser) init(base *src.PosBase, r io.Reader, errh ErrorHandler, pragh P ) p.first = nil + p.errcnt = 0 p.pragma = 0 p.fnest = 0 @@ -114,6 +116,7 @@ func (p *parser) error_at(pos src.Pos, msg string) { if p.first == nil { p.first = err } + p.errcnt++ if p.errh == nil { panic(p.first) } @@ -179,7 +182,6 @@ const stopset uint64 = 1<<_Break | 1<<_Defer | 1<<_Fallthrough | 1<<_For | - 1<<_Func | 1<<_Go | 1<<_Goto | 1<<_If | @@ -495,17 +497,18 @@ func (p *parser) funcDeclOrNil() *FuncDecl { } func (p *parser) funcBody() *BlockStmt { - // TODO(gri) If we are in a function we should update p.fnest - // accordingly. Currently p.fnest is always zero and thus not - // used in error recovery. - // Not enabled because it performs worse for some code without - // more fine tuning (see example in #22164). - // p.fnest++ + p.fnest++ + errcnt := p.errcnt body := p.blockStmt("") - // p.fnest-- - if p.mode&CheckBranches != 0 { + p.fnest-- + + // Don't check branches if there were syntax errors in the function + // as it may lead to spurious errors (e.g., see test/switch2.go) or + // possibly crashes due to incomplete syntax trees. + if p.mode&CheckBranches != 0 && errcnt == p.errcnt { checkBranches(body, p.errh) } + return body } diff --git a/test/fixedbugs/issue14006.go b/test/fixedbugs/issue14006.go index d69bdd4892..02041cc290 100644 --- a/test/fixedbugs/issue14006.go +++ b/test/fixedbugs/issue14006.go @@ -50,7 +50,10 @@ func f() { labelname: // ERROR "missing statement after label" case false: } +} +func g() { + var z bool switch { case z: labelname: // ERROR "label labelname defined and not used" -- 2.48.1