2015-01-19 12:59:58 -07:00
|
|
|
// 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
|
|
|
|
|
2021-01-01 05:51:22 -07:00
|
|
|
var never bool
|
|
|
|
|
2015-01-19 12:59:58 -07:00
|
|
|
func main() {
|
2015-01-29 08:33:19 -07:00
|
|
|
{
|
|
|
|
type X struct {
|
|
|
|
v int
|
|
|
|
}
|
|
|
|
var x X
|
|
|
|
func() {
|
|
|
|
x.v++
|
|
|
|
}()
|
|
|
|
if x.v != 1 {
|
|
|
|
panic("x.v != 1")
|
|
|
|
}
|
2015-01-19 12:59:58 -07:00
|
|
|
|
2015-01-29 08:33:19 -07:00
|
|
|
type Y struct {
|
|
|
|
X
|
|
|
|
}
|
|
|
|
var y Y
|
|
|
|
func() {
|
|
|
|
y.v = 1
|
|
|
|
}()
|
|
|
|
if y.v != 1 {
|
|
|
|
panic("y.v != 1")
|
|
|
|
}
|
2015-01-19 12:59:58 -07:00
|
|
|
}
|
|
|
|
|
2015-01-29 08:33:19 -07:00
|
|
|
{
|
|
|
|
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")
|
2015-01-19 12:59:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-29 08:33:19 -07:00
|
|
|
{
|
|
|
|
w := 0
|
|
|
|
tmp := 0
|
|
|
|
f := func() {
|
|
|
|
if w != 1 {
|
|
|
|
panic("w != 1")
|
|
|
|
}
|
2015-01-19 12:59:58 -07:00
|
|
|
}
|
|
|
|
func() {
|
2015-01-29 08:33:19 -07:00
|
|
|
tmp = w // force capture of w, but do not write to it yet
|
|
|
|
_ = tmp
|
2015-01-19 12:59:58 -07:00
|
|
|
func() {
|
2015-01-29 08:33:19 -07:00
|
|
|
func() {
|
|
|
|
w++ // write in a nested closure
|
|
|
|
}()
|
2015-01-19 12:59:58 -07:00
|
|
|
}()
|
|
|
|
}()
|
2015-01-29 08:33:19 -07:00
|
|
|
f()
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
var g func() int
|
cmd/compile: experimental loop iterator capture semantics change
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>
2022-06-12 13:33:57 -06:00
|
|
|
var i int
|
|
|
|
for i = range [2]int{} {
|
2015-01-29 08:33:19 -07:00
|
|
|
if i == 0 {
|
|
|
|
g = func() int {
|
2019-09-08 10:36:13 -06:00
|
|
|
return i // test that we capture by ref here, i is mutated on every interaction
|
2015-01-29 08:33:19 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
2019-09-08 10:36:13 -06:00
|
|
|
// q++ must on a different decldepth than q declaration
|
2015-01-29 08:33:19 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
2019-09-08 10:36:13 -06:00
|
|
|
// q++ must on a different decldepth than q declaration
|
2015-01-29 08:33:19 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if g() != 2 {
|
|
|
|
panic("g() != 2")
|
|
|
|
}
|
|
|
|
}
|
2021-01-01 05:51:22 -07:00
|
|
|
|
|
|
|
{
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
}
|
2015-01-19 12:59:58 -07:00
|
|
|
}
|