From: Robert Griesemer Date: Thu, 25 Aug 2022 23:14:43 +0000 (-0700) Subject: cmd/compile/internal/syntax: use BadExpr instead of fake CallExpr in bad go/defer X-Git-Tag: go1.20rc1~1291 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c801e4b10f708c180a3708bcf39881338691287c;p=gostls13.git cmd/compile/internal/syntax: use BadExpr instead of fake CallExpr in bad go/defer If the go/defer syntax is bad, using a fake CallExpr may produce a follow-on error in the type checker. Instead store a BadExpr in the syntax tree (since an error has already been reported). Adjust various tests. For #54511. Change-Id: Ib2d25f8eab7d5745275188d83d11620cad6ef47c Reviewed-on: https://go-review.googlesource.com/c/go/+/425675 Reviewed-by: Alan Donovan TryBot-Result: Gopher Robot Run-TryBot: Robert Griesemer Auto-Submit: Robert Griesemer Reviewed-by: Robert Griesemer --- diff --git a/src/cmd/compile/internal/syntax/nodes.go b/src/cmd/compile/internal/syntax/nodes.go index b0a0918e77..10af3c597b 100644 --- a/src/cmd/compile/internal/syntax/nodes.go +++ b/src/cmd/compile/internal/syntax/nodes.go @@ -385,7 +385,7 @@ type ( CallStmt struct { Tok token // Go or Defer - Call *CallExpr + Call Expr stmt } diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index 3bf9a5cb3b..8ae2ebbe76 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -951,16 +951,21 @@ func (p *parser) callStmt() *CallStmt { x = t } - cx, ok := x.(*CallExpr) - if !ok { - p.errorAt(x.Pos(), fmt.Sprintf("expression in %s must be function call", s.Tok)) - // already progressed, no need to advance - cx = new(CallExpr) - cx.pos = x.Pos() - cx.Fun = x // assume common error of missing parentheses (function invocation) + // TODO(gri) Now that we don't store a CallExpr in a CallStmt anymore + // we might as well leave this check to the type checker. + // Adjust this here and in go/parser eventually. + if _, ok := x.(*CallExpr); !ok { + // only report an error if it's a new one + if bad, ok := x.(*BadExpr); !ok { + p.errorAt(x.Pos(), fmt.Sprintf("expression in %s must be function call", s.Tok)) + // already progressed, no need to advance + bad = new(BadExpr) + bad.pos = x.Pos() + x = bad + } } - s.Call = cx + s.Call = x return s } diff --git a/src/cmd/compile/internal/syntax/testdata/issue20789.go b/src/cmd/compile/internal/syntax/testdata/issue20789.go index 5f150db7e6..0d5988b9a6 100644 --- a/src/cmd/compile/internal/syntax/testdata/issue20789.go +++ b/src/cmd/compile/internal/syntax/testdata/issue20789.go @@ -6,4 +6,4 @@ // Line 9 must end in EOF for this test (no newline). package e -func([<-chan<-[func /* ERROR unexpected u */ u){go /* ERROR must be function call */ \ No newline at end of file +func([<-chan<-[func /* ERROR unexpected u */ u){go \ No newline at end of file diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index 74d4164ba9..92aa6b6f76 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -165,7 +165,7 @@ func (check *Checker) closeScope() { check.scope = check.scope.Parent() } -func (check *Checker) suspendedCall(keyword string, call *syntax.CallExpr) { +func (check *Checker) suspendedCall(keyword string, call syntax.Expr) { var x operand var msg string switch check.rawExpr(&x, call, nil, false) { diff --git a/src/cmd/compile/internal/types2/testdata/check/stmt0.go b/src/cmd/compile/internal/types2/testdata/check/stmt0.go index e5b6f5dff7..7aaa83e4ff 100644 --- a/src/cmd/compile/internal/types2/testdata/check/stmt0.go +++ b/src/cmd/compile/internal/types2/testdata/check/stmt0.go @@ -229,7 +229,7 @@ func selects() { } func gos() { - go 1 /* ERROR must be function call */ /* ERROR cannot call non-function */ + go 1 /* ERROR must be function call */ go int /* ERROR "go requires function call, not conversion" */ (0) go gos() var c chan int @@ -238,7 +238,7 @@ func gos() { } func defers() { - defer 1 /* ERROR must be function call */ /* ERROR cannot call non-function */ + defer 1 /* ERROR must be function call */ defer int /* ERROR "defer requires function call, not conversion" */ (0) defer defers() var c chan int diff --git a/test/fixedbugs/issue20789.go b/test/fixedbugs/issue20789.go index 82aec965ed..4e4eed42a7 100644 --- a/test/fixedbugs/issue20789.go +++ b/test/fixedbugs/issue20789.go @@ -10,4 +10,4 @@ // there yet, so put it here for now. See also #20800.) package e -func([<-chan<-[func u){go // ERROR "unexpected u", ERROR "must be function call" \ No newline at end of file +func([<-chan<-[func u){go // ERROR "unexpected u" \ No newline at end of file diff --git a/test/fixedbugs/issue23586.go b/test/fixedbugs/issue23586.go index c2d4c9ffb5..31d39d8389 100644 --- a/test/fixedbugs/issue23586.go +++ b/test/fixedbugs/issue23586.go @@ -11,13 +11,15 @@ package p +// TODO(gri) The "not used" errors should not be reported. + import ( - "fmt" - "math" + "fmt" // ERROR "imported and not used" + "math" // ERROR "imported and not used" ) func f() { - var i int + var i int // ERROR "i declared but not used" defer func() { fmt.Println() } // ERROR "must be function call" go func() { _ = math.Sin(0) } // ERROR "must be function call" go func() { _ = i} // ERROR "must be function call"