var v_used bool
if ident != nil {
if _, obj := check.scope.LookupParent(ident.Name, token.NoPos); obj != nil {
- v, _ = obj.(*Var)
- if v != nil {
+ // It's ok to mark non-local variables, but ignore variables
+ // from other packages to avoid potential race conditions with
+ // dot-imported variables.
+ if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
+ v = w
v_used = v.used
}
}
l := len(lhs)
get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2)
if get == nil {
+ check.useLHS(lhs...)
return // error reported by unpack
}
if l != r {
// use type-checks each argument.
// Useful to make sure expressions are evaluated
// (and variables are "used") in the presence of other errors.
+// The arguments may be nil.
func (check *Checker) use(arg ...ast.Expr) {
var x operand
for _, e := range arg {
- if e != nil { // be safe
+ // The nil check below is necessary since certain AST fields
+ // may legally be nil (e.g., the ast.SliceExpr.High field).
+ if e != nil {
check.rawExpr(&x, e, nil)
}
}
}
+// useLHS is like use, but doesn't "use" top-level identifiers.
+// It should be called instead of use if the arguments are
+// expressions on the lhs of an assignment.
+// The arguments must not be nil.
+func (check *Checker) useLHS(arg ...ast.Expr) {
+ var x operand
+ for _, e := range arg {
+ // If the lhs is an identifier denoting a variable v, this assignment
+ // is not a 'use' of v. Remember current value of v.used and restore
+ // after evaluating the lhs via check.rawExpr.
+ var v *Var
+ var v_used bool
+ if ident, _ := unparen(e).(*ast.Ident); ident != nil {
+ // never type-check the blank name on the lhs
+ if ident.Name == "_" {
+ continue
+ }
+ if _, obj := check.scope.LookupParent(ident.Name, token.NoPos); obj != nil {
+ // It's ok to mark non-local variables, but ignore variables
+ // from other packages to avoid potential race conditions with
+ // dot-imported variables.
+ if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
+ v = w
+ v_used = v.used
+ }
+ }
+ }
+ check.rawExpr(&x, e, nil)
+ if v != nil {
+ v.used = v_used // restore v.used
+ }
+ }
+}
+
// useGetter is like use, but takes a getter instead of a list of expressions.
// It should be called instead of use if a getter is present to avoid repeated
// evaluation of the first argument (since the getter was likely obtained via
if typ != nil {
t := check.typ(typ)
if !isConstType(t) {
- check.errorf(typ.Pos(), "invalid constant type %s", t)
+ // don't report an error if the type is an invalid C (defined) type
+ // (issue #22090)
+ if t.Underlying() != Typ[Invalid] {
+ check.errorf(typ.Pos(), "invalid constant type %s", t)
+ }
obj.typ = Typ[Invalid]
return
}
// declaration, but the post statement must not."
if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
check.softErrorf(s.Pos(), "cannot declare in post statement")
+ // Don't call useLHS here because we want to use the lhs in
+ // this errroneous statement so that we don't get errors about
+ // these lhs variables being declared but not used.
check.use(s.Lhs...) // avoid follow-up errors
}
check.stmt(inner, s.Body)
import _ /* ERROR cannot rename import "C" */ "C"
import foo /* ERROR cannot rename import "C" */ "C"
import . /* ERROR cannot rename import "C" */ "C"
+
+// Test cases extracted from issue #22090.
+
+import "unsafe"
+
+const _ C.int = 0xff // no error due to invalid constant type
+
+type T struct {
+ Name string
+ Ordinal int
+}
+
+func f(args []T) {
+ var s string
+ for i, v := range args {
+ cname := C.CString(v.Name)
+ args[i].Ordinal = int(C.sqlite3_bind_parameter_index(s, cname)) // no error due to i not being "used"
+ C.free(unsafe.Pointer(cname))
+ }
+}
+
+type CType C.Type
+
+const _ CType = C.X // no error due to invalid constant type
+const _ = C.X
}
case *Var:
+ // It's ok to mark non-local variables, but ignore variables
+ // from other packages to avoid potential race conditions with
+ // dot-imported variables.
if obj.pkg == check.pkg {
obj.used = true
}