Compiler errors for syntactically invalid code

227 views
Skip to first unread message

Matthew Dempsky

unread,
Jun 27, 2016, 6:41:06 PM6/27/16
to golang-dev
cmd/compile and gccgo recognize a handful of special-case syntax error cases.  For example:

    package p

    func f() {
    for var i = 0; i < 10; i++ {    // var declaration not allowed in for initializer
    }
    }

    func g()
    {    // unexpected semicolon or newline before '{'
    }

I imagine they were originally present to help C developers adapt to Go syntax, but are these error messages still worth maintaining today?

For example, it seems common practice nowadays that Go developers configure cmd/gofmt to run automatically whenever they save a file, so they'll first see go/parser's generic "expected operand, found 'var'" and "expected declaration, found '{'" errors instead.

More generally, how concerned are we about compiler errors for syntactically invalid code?  If gofmt gives a generic error message in a case, is it okay for the compilers to do the same?  Or do we hold the compilers to a higher standard?

Robert Griesemer

unread,
Jun 27, 2016, 6:53:28 PM6/27/16
to Matthew Dempsky, golang-dev
rsc put in some effort to produce better error where generic (yacc) error messages were not great. Specifically, the original yacc grammar had the list of special cases below (see end of mail).

Some of them are more clearly handled w/o extra effort by the recursive-descent parser, for others I added extra code. The two examples above are from that list.

I'd say leave them for now since they don't really cost (especially if we have tests) unless the default error message is sufficiently clear.

Also, gofmt (go/parser) has never produced exactly the same error messages; and more often than not, go/parser was adjusted to produce an error message matching the compiler better. So, in some sense, the compilers are at a higher standard (more work went into good error messages), but occasionally, gofmt is doing a better job automatically.

- gri


%error loadsys package LIMPORT '(' LLITERAL import_package import_there ',':
"unexpected comma during import block"

%error loadsys package LIMPORT LNAME ';':
"missing import path; require quoted string"

%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';':
"missing { after if clause"

%error loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';':
"missing { after switch clause"

%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';':
"missing { after for clause"

%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY:
"missing { after for clause"

%error loadsys package imports LFUNC LNAME '(' ')' ';' '{':
"unexpected semicolon or newline before {"

%error loadsys package imports LTYPE LNAME ';':
"unexpected semicolon or newline in type declaration"

%error loadsys package imports LCHAN '}':
"unexpected } in channel type"

%error loadsys package imports LCHAN ')':
"unexpected ) in channel type"

%error loadsys package imports LCHAN ',':
"unexpected comma in channel type"

%error loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE:
"unexpected semicolon or newline before else"

%error loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME:
"name list not allowed in interface type"

%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME:
"var declaration not allowed in for initializer"

%error loadsys package imports LVAR LNAME '[' ']' LNAME '{':
"unexpected { at end of statement"

%error loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{':
"unexpected { at end of statement"

%error loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';':
"argument to go/defer must be function call"

%error loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';':
"need trailing comma before newline in composite literal"

%error loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';':
"need trailing comma before newline in composite literal"

%error loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME:
"nested func not allowed"

%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';':
"else must be followed by if or statement block"

--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Ian Lance Taylor

unread,
Jun 27, 2016, 7:38:48 PM6/27/16
to Matthew Dempsky, golang-dev
On Mon, Jun 27, 2016 at 3:40 PM, 'Matthew Dempsky' via golang-dev
<golan...@googlegroups.com> wrote:
> cmd/compile and gccgo recognize a handful of special-case syntax error
> cases. For example:
>
> package p
>
> func f() {
> for var i = 0; i < 10; i++ { // var declaration not allowed in for
> initializer
> }
> }
>
> func g()
> { // unexpected semicolon or newline before '{'
> }
>
> I imagine they were originally present to help C developers adapt to Go
> syntax, but are these error messages still worth maintaining today?

I don't think that was the original motivation. I think Russ got
interested in it while working on his blog post
http://research.swtch.com/yyerror .

Ian

Matthew Dempsky

unread,
Jun 27, 2016, 7:47:21 PM6/27/16
to Ian Lance Taylor, golang-dev
On Mon, Jun 27, 2016 at 4:38 PM, Ian Lance Taylor <ia...@golang.org> wrote:
I don't think that was the original motivation.  I think Russ got
interested in it while working on his blog post
http://research.swtch.com/yyerror .

Ah, you're right.  They appear to have been added in https://golang.org/cl/194085, which was ~6 months after gofmt was first added.
Reply all
Reply to author
Forward
0 new messages