mirror of
				https://github.com/golang/go.git
				synced 2025-11-03 18:20:59 +00:00 
			
		
		
		
	Adds:
GOEXPERIMENT=loopvar (expected way of invoking)
-d=loopvar={-1,0,1,2,11,12} (for per-package control and/or logging)
-d=loopvarhash=... (for hash debugging)
loopvar=11,12 are for testing, benchmarking, and debugging.
If enabled,for loops of the form `for x,y := range thing`, if x and/or
y are addressed or captured by a closure, are transformed by renaming
x/y to a temporary and prepending an assignment to the body of the
loop x := tmp_x.  This changes the loop semantics by making each
iteration's instance of x be distinct from the others (currently they
are all aliased, and when this matters, it is almost always a bug).
3-range with captured iteration variables are also transformed,
though it is a more complex transformation.
"Optimized" to do a simpler transformation for
3-clause for where the increment is empty.
(Prior optimization of address-taking under Return disabled, because
it was incorrect; returns can have loops for children.  Restored in
a later CL.)
Includes support for -d=loopvarhash=<binary string> intended for use
with hash search and GOCOMPILEDEBUG=loopvarhash=<binary string>
(use `gossahash -e loopvarhash command-that-fails`).
Minor feature upgrades to hash-triggered features; clients can specify
that file-position hashes use only the most-inline position, and/or that
they use only the basenames of source files (not the full directory path).
Most-inlined is the right choice for debugging loop-iteration change
once the semantics are linked to the package across inlining; basename-only
makes it tractable to write tests (which, otherwise, depend on the full
pathname of the source file and thus vary).
Updates #57969.
Change-Id: I180a51a3f8d4173f6210c861f10de23de8a1b1db
Reviewed-on: https://go-review.googlesource.com/c/go/+/411904
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
		
	
			
		
			
				
	
	
		
			133 lines
		
	
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			133 lines
		
	
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// run
 | 
						|
 | 
						|
// Copyright 2015 The Go Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
// Check that these do not use "by value" capturing,
 | 
						|
// because changes are made to the value during the closure.
 | 
						|
 | 
						|
package main
 | 
						|
 | 
						|
var never bool
 | 
						|
 | 
						|
func main() {
 | 
						|
	{
 | 
						|
		type X struct {
 | 
						|
			v int
 | 
						|
		}
 | 
						|
		var x X
 | 
						|
		func() {
 | 
						|
			x.v++
 | 
						|
		}()
 | 
						|
		if x.v != 1 {
 | 
						|
			panic("x.v != 1")
 | 
						|
		}
 | 
						|
 | 
						|
		type Y struct {
 | 
						|
			X
 | 
						|
		}
 | 
						|
		var y Y
 | 
						|
		func() {
 | 
						|
			y.v = 1
 | 
						|
		}()
 | 
						|
		if y.v != 1 {
 | 
						|
			panic("y.v != 1")
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		type Z struct {
 | 
						|
			a [3]byte
 | 
						|
		}
 | 
						|
		var z Z
 | 
						|
		func() {
 | 
						|
			i := 0
 | 
						|
			for z.a[1] = 1; i < 10; i++ {
 | 
						|
			}
 | 
						|
		}()
 | 
						|
		if z.a[1] != 1 {
 | 
						|
			panic("z.a[1] != 1")
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		w := 0
 | 
						|
		tmp := 0
 | 
						|
		f := func() {
 | 
						|
			if w != 1 {
 | 
						|
				panic("w != 1")
 | 
						|
			}
 | 
						|
		}
 | 
						|
		func() {
 | 
						|
			tmp = w // force capture of w, but do not write to it yet
 | 
						|
			_ = tmp
 | 
						|
			func() {
 | 
						|
				func() {
 | 
						|
					w++ // write in a nested closure
 | 
						|
				}()
 | 
						|
			}()
 | 
						|
		}()
 | 
						|
		f()
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		var g func() int
 | 
						|
		var i int
 | 
						|
		for i = range [2]int{} {
 | 
						|
			if i == 0 {
 | 
						|
				g = func() int {
 | 
						|
					return i // test that we capture by ref here, i is mutated on every interaction
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if g() != 1 {
 | 
						|
			panic("g() != 1")
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		var g func() int
 | 
						|
		q := 0
 | 
						|
		for range [2]int{} {
 | 
						|
			q++
 | 
						|
			g = func() int {
 | 
						|
				return q // test that we capture by ref here
 | 
						|
				// q++ must on a different decldepth than q declaration
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if g() != 2 {
 | 
						|
			panic("g() != 2")
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		var g func() int
 | 
						|
		var a [2]int
 | 
						|
		q := 0
 | 
						|
		for a[func() int {
 | 
						|
			q++
 | 
						|
			return 0
 | 
						|
		}()] = range [2]int{} {
 | 
						|
			g = func() int {
 | 
						|
				return q // test that we capture by ref here
 | 
						|
				// q++ must on a different decldepth than q declaration
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if g() != 2 {
 | 
						|
			panic("g() != 2")
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		var g func() int
 | 
						|
		q := 0
 | 
						|
		q, g = 1, func() int { return q }
 | 
						|
		if never {
 | 
						|
			g = func() int { return 2 }
 | 
						|
		}
 | 
						|
		if g() != 1 {
 | 
						|
			panic("g() != 1")
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |