diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index fcf4f5b692050..1ed20651b1088 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -28,6 +28,8 @@ type parser struct { nerrors int // error count } +type parserError string // for error recovery if no error handler was installed + func (p *parser) init(src io.Reader, errh ErrorHandler, pragh PragmaHandler) { p.scanner.init(src, func(pos, line int, msg string) { p.nerrors++ @@ -35,7 +37,7 @@ func (p *parser) init(src io.Reader, errh ErrorHandler, pragh PragmaHandler) { errh(pos, line, msg) return } - panic(fmt.Sprintf("%d: %s\n", line, msg)) + panic(parserError(fmt.Sprintf("%d: %s\n", line, msg))) }, pragh) p.fnest = 0 diff --git a/src/cmd/compile/internal/syntax/parser_test.go b/src/cmd/compile/internal/syntax/parser_test.go index 8e6b77d0c687e..780f10835cff7 100644 --- a/src/cmd/compile/internal/syntax/parser_test.go +++ b/src/cmd/compile/internal/syntax/parser_test.go @@ -155,3 +155,10 @@ func verifyPrint(filename string, ast1 *File) { panic("not equal") } } + +func TestIssue17697(t *testing.T) { + _, err := ReadBytes(nil, nil, nil, 0) // return with parser error, don't panic + if err == nil { + t.Errorf("no error reported") + } +} diff --git a/src/cmd/compile/internal/syntax/syntax.go b/src/cmd/compile/internal/syntax/syntax.go index 49831d0fbd03e..71fc097c3b2ec 100644 --- a/src/cmd/compile/internal/syntax/syntax.go +++ b/src/cmd/compile/internal/syntax/syntax.go @@ -5,6 +5,7 @@ package syntax import ( + "errors" "fmt" "io" "os" @@ -52,18 +53,31 @@ func ReadBytes(src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (* return Read(&bytesReader{src}, errh, pragh, mode) } -func Read(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) { +func Read(src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (ast *File, err error) { + defer func() { + if p := recover(); p != nil { + if msg, ok := p.(parserError); ok { + err = errors.New(string(msg)) + return + } + panic(p) + } + }() + var p parser p.init(src, errh, pragh) - p.next() - ast := p.file() + ast = p.file() + // TODO(gri) This isn't quite right: Even if there's an error handler installed + // we should report an error if parsing found syntax errors. This also + // requires updating the noder's ReadFile call. if errh == nil && p.nerrors > 0 { - return nil, fmt.Errorf("%d syntax errors", p.nerrors) + ast = nil + err = fmt.Errorf("%d syntax errors", p.nerrors) } - return ast, nil + return } func Write(w io.Writer, n *File) error {