]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/syntax: consider function nesting for error recovery
authorgriesemer <gri@golang.org>
Tue, 10 Oct 2017 23:56:56 +0000 (16:56 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 11 Oct 2017 00:29:58 +0000 (00:29 +0000)
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 <gri@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/syntax/parser.go
test/fixedbugs/issue14006.go

index c04322890c0bf100e98afdacd5128a3df800c7b1..b77356a7e5062a077b9982bcd5166dacc66d9c8d 100644 (file)
@@ -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
 }
 
index d69bdd4892b91760a4fc458f7d3ed82678836197..02041cc290019fff8f2f5fdbfb3945987609911c 100644 (file)
@@ -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"