...

Source file src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/doc.go

Documentation: cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package loopclosure defines an Analyzer that checks for references to
     6  // enclosing loop variables from within nested functions.
     7  //
     8  // # Analyzer loopclosure
     9  //
    10  // loopclosure: check references to loop variables from within nested functions
    11  //
    12  // This analyzer reports places where a function literal references the
    13  // iteration variable of an enclosing loop, and the loop calls the function
    14  // in such a way (e.g. with go or defer) that it may outlive the loop
    15  // iteration and possibly observe the wrong value of the variable.
    16  //
    17  // Note: An iteration variable can only outlive a loop iteration in Go versions <=1.21.
    18  // In Go 1.22 and later, the loop variable lifetimes changed to create a new
    19  // iteration variable per loop iteration. (See go.dev/issue/60078.)
    20  //
    21  // In this example, all the deferred functions run after the loop has
    22  // completed, so all observe the final value of v [<go1.22].
    23  //
    24  //	for _, v := range list {
    25  //	    defer func() {
    26  //	        use(v) // incorrect
    27  //	    }()
    28  //	}
    29  //
    30  // One fix is to create a new variable for each iteration of the loop:
    31  //
    32  //	for _, v := range list {
    33  //	    v := v // new var per iteration
    34  //	    defer func() {
    35  //	        use(v) // ok
    36  //	    }()
    37  //	}
    38  //
    39  // After Go version 1.22, the previous two for loops are equivalent
    40  // and both are correct.
    41  //
    42  // The next example uses a go statement and has a similar problem [<go1.22].
    43  // In addition, it has a data race because the loop updates v
    44  // concurrent with the goroutines accessing it.
    45  //
    46  //	for _, v := range elem {
    47  //	    go func() {
    48  //	        use(v)  // incorrect, and a data race
    49  //	    }()
    50  //	}
    51  //
    52  // A fix is the same as before. The checker also reports problems
    53  // in goroutines started by golang.org/x/sync/errgroup.Group.
    54  // A hard-to-spot variant of this form is common in parallel tests:
    55  //
    56  //	func Test(t *testing.T) {
    57  //	    for _, test := range tests {
    58  //	        t.Run(test.name, func(t *testing.T) {
    59  //	            t.Parallel()
    60  //	            use(test) // incorrect, and a data race
    61  //	        })
    62  //	    }
    63  //	}
    64  //
    65  // The t.Parallel() call causes the rest of the function to execute
    66  // concurrent with the loop [<go1.22].
    67  //
    68  // The analyzer reports references only in the last statement,
    69  // as it is not deep enough to understand the effects of subsequent
    70  // statements that might render the reference benign.
    71  // ("Last statement" is defined recursively in compound
    72  // statements such as if, switch, and select.)
    73  //
    74  // See: https://golang.org/doc/go_faq.html#closures_and_goroutines
    75  package loopclosure
    76  

View as plain text