}
}
- if typ.Results != nil {
- for _, field := range typ.Results.List {
- expr := field.Type
- if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
- f.Badf(expr.Pos(), "%s returns lock by value: %v", name, path)
- }
- }
- }
+ // Don't check typ.Results. If T has a Lock field it's OK to write
+ // return T{}
+ // because that is returning the zero value. Leave result checking
+ // to the return statement.
}
// checkCopyLocksRange checks whether a range statement
if _, ok := x.(*ast.CompositeLit); ok {
return nil
}
+ if _, ok := x.(*ast.CallExpr); ok {
+ // A call may return a zero value.
+ return nil
+ }
+ if star, ok := x.(*ast.StarExpr); ok {
+ if _, ok := star.X.(*ast.CallExpr); ok {
+ // A call may return a pointer to a zero value.
+ return nil
+ }
+ }
return lockPath(f.pkg.typesPkg, f.pkg.types[x].Type)
}
func OkFunc(*sync.Mutex) {}
func BadFunc(sync.Mutex) {} // ERROR "BadFunc passes lock by value: sync.Mutex"
func OkRet() *sync.Mutex {}
-func BadRet() sync.Mutex {} // ERROR "BadRet returns lock by value: sync.Mutex"
+func BadRet() sync.Mutex {} // Don't warn about results
var (
OkClosure = func(*sync.Mutex) {}
func OkFunc(e *EmbeddedRWMutex) {}
func BadFunc(EmbeddedRWMutex) {} // ERROR "BadFunc passes lock by value: testdata.EmbeddedRWMutex"
func OkRet() *EmbeddedRWMutex {}
-func BadRet() EmbeddedRWMutex {} // ERROR "BadRet returns lock by value: testdata.EmbeddedRWMutex"
+func BadRet() EmbeddedRWMutex {} // Don't warn about results
type FieldMutex struct {
s sync.Mutex
}
}
+// Some cases that we don't warn about.
+
+func AcceptedCases() {
+ x := EmbeddedRwMutex{} // composite literal on RHS is OK (#16227)
+ x = BadRet() // function call on RHS is OK (#16227)
+ x = *OKRet() // indirection of function call on RHS is OK (#16227)
+}
+
// TODO: Unfortunate cases
// Non-ideal error message: