Skip to content

Commit

Permalink
go/types: fewer spurious "declared but not used" follow-on errors
Browse files Browse the repository at this point in the history
Mark variables as used even when they appear within an expression
context which we can't type-check; e.g., because the expression is
erroneous, or comes from an import "C" declaration.

Fixes #20358.

Change-Id: Ib28cc78d3867c597c7a1ace54de09ada02f5b33a
Reviewed-on: https://go-review.googlesource.com/43500
Reviewed-by: Alan Donovan <adonovan@google.com>
  • Loading branch information
griesemer committed May 15, 2017
1 parent 27da3ba commit 5088b64
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/go/types/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
func (check *Checker) use(arg ...ast.Expr) {
var x operand
for _, e := range arg {
check.rawExpr(&x, e, nil)
if e != nil { // be safe
check.rawExpr(&x, e, nil)
}
}
}

Expand Down
13 changes: 13 additions & 0 deletions src/go/types/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,17 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
}

default:
// when "using" all elements unpack KeyValueExpr
// explicitly because check.use doesn't accept them
for _, e := range e.Elts {
if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
// Ideally, we should also "use" kv.Key but we can't know
// if it's an externally defined struct key or not. Going
// forward anyway can lead to other errors. Give up instead.
e = kv.Value
}
check.use(e)
}
// if utyp is invalid, an error was reported before
if utyp != Typ[Invalid] {
check.errorf(e.Pos(), "invalid composite literal type %s", typ)
Expand All @@ -1182,6 +1193,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
case *ast.IndexExpr:
check.expr(x, e.X)
if x.mode == invalid {
check.use(e.Index)
goto Error
}

Expand Down Expand Up @@ -1251,6 +1263,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
case *ast.SliceExpr:
check.expr(x, e.X)
if x.mode == invalid {
check.use(e.Low, e.High, e.Max)
goto Error
}

Expand Down
21 changes: 21 additions & 0 deletions src/go/types/testdata/issues.src
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,24 @@ func issue15755() {
_ = u
_ = v
}

// Test that we don't get "declared but not used"
// errors in the context of invalid/C objects.
func issue20358() {
var F C /* ERROR "undeclared" */ .F
var A C /* ERROR "undeclared" */ .A
var S C /* ERROR "undeclared" */ .S
type T C /* ERROR "undeclared" */ .T
type P C /* ERROR "undeclared" */ .P

// these variables must be "used" even though
// the LHS expressions/types below in which
// context they are used are unknown/invalid
var f, a, s1, s2, s3, t, p int

_ = F(f)
_ = A[a]
_ = S[s1:s2:s3]
_ = T{t}
_ = P{f: p}
}

0 comments on commit 5088b64

Please sign in to comment.