diff --git a/go/types/builtins.go b/go/types/builtins.go index 4ffafe3a0e8..cc70e2c28ee 100644 --- a/go/types/builtins.go +++ b/go/types/builtins.go @@ -19,6 +19,14 @@ import ( // false, and *x is undefined. // func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ bool) { + // append is the only built-in that permits the use of ... for the last argument + bin := predeclaredFuncs[id] + if call.Ellipsis.IsValid() && id != _Append { + check.invalidOp(call.Ellipsis, "invalid use of ... with built-in %s", bin.name) + check.use(call.Args) + return + } + // determine actual arguments var arg getter nargs := len(call.Args) @@ -34,14 +42,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b } } case _Make, _New, _Offsetof, _Trace: - // arguments requires special handling - } - - // append is the only built-in that permits the use of ... for the last argument - bin := predeclaredFuncs[id] - if call.Ellipsis.IsValid() && id != _Append { - check.invalidOp(call.Ellipsis, "invalid use of ... with built-in %s", bin.name) - return + // arguments require special handling } // check argument count diff --git a/go/types/call.go b/go/types/call.go index 7dd7bd4dcf4..f665b2cc091 100644 --- a/go/types/call.go +++ b/go/types/call.go @@ -16,12 +16,7 @@ func (check *checker) call(x *operand, e *ast.CallExpr) exprKind { switch x.mode { case invalid: - // We don't have a valid call or conversion but we have a list of arguments. - // Typecheck them independently for better partial type information in - // the presence of type errors. - for _, arg := range e.Args { - check.expr(x, arg) - } + check.use(e.Args) x.mode = invalid x.expr = e return statement @@ -85,6 +80,16 @@ func (check *checker) call(x *operand, e *ast.CallExpr) exprKind { } } +// use type-checks each list element. +// Useful to make sure a list of expressions is evaluated +// (and variables are "used") in the presence of other errors. +func (check *checker) use(list []ast.Expr) { + var x operand + for _, e := range list { + check.rawExpr(&x, e, nil) + } +} + // TODO(gri) use unpack for assignment checking as well. // A getter sets x as the i'th operand, where 0 <= i < n and n is the total diff --git a/go/types/testdata/builtins.src b/go/types/testdata/builtins.src index ce75d0ed5bd..12898051b06 100644 --- a/go/types/testdata/builtins.src +++ b/go/types/testdata/builtins.src @@ -629,7 +629,6 @@ func Offsetof1() { _ = unsafe.Offsetof(y2 /* ERROR method value */ .m) var s []byte - _ = s _ = unsafe.Offsetof(s... /* ERROR invalid use of \.\.\. */ ) } @@ -731,7 +730,6 @@ func trace1() { // _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar") var s []byte - _ = s trace(s... /* ERROR invalid use of \.\.\. */ ) }