| // Copyright 2023 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. |
| |
| //go:build go1.22 |
| |
| package main |
| |
| import ( |
| "reflect" |
| ) |
| |
| func main() { |
| test_init() |
| bound() |
| manyvars() |
| nocond() |
| nopost() |
| address_sequences() |
| post_escapes() |
| |
| // Clones from cmd/compile/internal/loopvar/testdata . |
| for_complicated_esc_address() |
| for_esc_address() |
| for_esc_closure() |
| for_esc_method() |
| } |
| |
| // After go1.22, each i will have a distinct address and value. |
| var distinct = func(m, n int) []*int { |
| var r []*int |
| for i := m; i <= n; i++ { |
| r = append(r, &i) |
| } |
| return r |
| }(3, 5) |
| |
| func test_init() { |
| if len(distinct) != 3 { |
| panic(distinct) |
| } |
| for i, v := range []int{3, 4, 5} { |
| if v != *(distinct[i]) { |
| panic(distinct) |
| } |
| } |
| } |
| |
| func bound() { |
| b := func(k int) func() int { |
| var f func() int |
| for i := 0; i < k; i++ { |
| f = func() int { return i } // address before post updates i. So last value in the body. |
| } |
| return f |
| } |
| |
| if got := b(0); got != nil { |
| panic(got) |
| } |
| if got := b(5); got() != 4 { |
| panic(got()) |
| } |
| } |
| |
| func manyvars() { |
| // Tests declaring many variables and having one in the middle escape. |
| var f func() int |
| for i, j, k, l, m, n, o, p := 7, 6, 5, 4, 3, 2, 1, 0; p < 6; l, p = l+1, p+1 { |
| _, _, _, _, _, _, _, _ = i, j, k, l, m, n, o, p |
| f = func() int { return l } // address *before* post updates l |
| } |
| if f() != 9 { // l == p+4 |
| panic(f()) |
| } |
| } |
| |
| func nocond() { |
| var c, b, e *int |
| for p := 0; ; p++ { |
| if p%7 == 0 { |
| c = &p |
| continue |
| } else if p == 20 { |
| b = &p |
| break |
| } |
| e = &p |
| } |
| |
| if *c != 14 { |
| panic(c) |
| } |
| if *b != 20 { |
| panic(b) |
| } |
| if *e != 19 { |
| panic(e) |
| } |
| } |
| |
| func nopost() { |
| var first, last *int |
| for p := 0; p < 20; { |
| if first == nil { |
| first = &p |
| } |
| last = &p |
| |
| p++ |
| } |
| |
| if *first != 1 { |
| panic(first) |
| } |
| if *last != 20 { |
| panic(last) |
| } |
| } |
| |
| func address_sequences() { |
| var c, b, p []*int |
| |
| cond := func(x *int) bool { |
| c = append(c, x) |
| return *x < 5 |
| } |
| body := func(x *int) { |
| b = append(b, x) |
| } |
| post := func(x *int) { |
| p = append(p, x) |
| (*x)++ |
| } |
| for i := 0; cond(&i); post(&i) { |
| body(&i) |
| } |
| |
| if c[0] == c[1] { |
| panic(c) |
| } |
| |
| if !reflect.DeepEqual(c[:5], b) { |
| panic(c) |
| } |
| |
| if !reflect.DeepEqual(c[1:], p) { |
| panic(c) |
| } |
| |
| if !reflect.DeepEqual(b[1:], p[:4]) { |
| panic(b) |
| } |
| } |
| |
| func post_escapes() { |
| var p []*int |
| post := func(x *int) { |
| p = append(p, x) |
| (*x)++ |
| } |
| |
| for i := 0; i < 5; post(&i) { |
| } |
| |
| var got []int |
| for _, x := range p { |
| got = append(got, *x) |
| } |
| if want := []int{1, 2, 3, 4, 5}; !reflect.DeepEqual(got, want) { |
| panic(got) |
| } |
| } |
| |
| func for_complicated_esc_address() { |
| // Clone of for_complicated_esc_adress.go |
| ss, sa := shared(23) |
| ps, pa := private(23) |
| es, ea := experiment(23) |
| |
| if ss != ps || ss != es || ea != pa || sa == pa { |
| println("shared s, a", ss, sa, "; private, s, a", ps, pa, "; experiment s, a", es, ea) |
| panic("for_complicated_esc_address") |
| } |
| } |
| |
| func experiment(x int) (int, int) { |
| sum := 0 |
| var is []*int |
| for i := x; i != 1; i = i / 2 { |
| for j := 0; j < 10; j++ { |
| if i == j { // 10 skips |
| continue |
| } |
| sum++ |
| } |
| i = i*3 + 1 |
| if i&1 == 0 { |
| is = append(is, &i) |
| for i&2 == 0 { |
| i = i >> 1 |
| } |
| } else { |
| i = i + i |
| } |
| } |
| |
| asum := 0 |
| for _, pi := range is { |
| asum += *pi |
| } |
| |
| return sum, asum |
| } |
| |
| func private(x int) (int, int) { |
| sum := 0 |
| var is []*int |
| I := x |
| for ; I != 1; I = I / 2 { |
| i := I |
| for j := 0; j < 10; j++ { |
| if i == j { // 10 skips |
| I = i |
| continue |
| } |
| sum++ |
| } |
| i = i*3 + 1 |
| if i&1 == 0 { |
| is = append(is, &i) |
| for i&2 == 0 { |
| i = i >> 1 |
| } |
| } else { |
| i = i + i |
| } |
| I = i |
| } |
| |
| asum := 0 |
| for _, pi := range is { |
| asum += *pi |
| } |
| |
| return sum, asum |
| } |
| |
| func shared(x int) (int, int) { |
| sum := 0 |
| var is []*int |
| i := x |
| for ; i != 1; i = i / 2 { |
| for j := 0; j < 10; j++ { |
| if i == j { // 10 skips |
| continue |
| } |
| sum++ |
| } |
| i = i*3 + 1 |
| if i&1 == 0 { |
| is = append(is, &i) |
| for i&2 == 0 { |
| i = i >> 1 |
| } |
| } else { |
| i = i + i |
| } |
| } |
| |
| asum := 0 |
| for _, pi := range is { |
| asum += *pi |
| } |
| return sum, asum |
| } |
| |
| func for_esc_address() { |
| // Clone of for_esc_address.go |
| sum := 0 |
| var is []*int |
| for i := 0; i < 10; i++ { |
| for j := 0; j < 10; j++ { |
| if i == j { // 10 skips |
| continue |
| } |
| sum++ |
| } |
| if i&1 == 0 { |
| is = append(is, &i) |
| } |
| } |
| |
| bug := false |
| if sum != 100-10 { |
| println("wrong sum, expected", 90, ", saw", sum) |
| bug = true |
| } |
| if len(is) != 5 { |
| println("wrong iterations, expected ", 5, ", saw", len(is)) |
| bug = true |
| } |
| sum = 0 |
| for _, pi := range is { |
| sum += *pi |
| } |
| if sum != 0+2+4+6+8 { |
| println("wrong sum, expected ", 20, ", saw ", sum) |
| bug = true |
| } |
| if bug { |
| panic("for_esc_address") |
| } |
| } |
| |
| func for_esc_closure() { |
| var is []func() int |
| |
| // Clone of for_esc_closure.go |
| sum := 0 |
| for i := 0; i < 10; i++ { |
| for j := 0; j < 10; j++ { |
| if i == j { // 10 skips |
| continue |
| } |
| sum++ |
| } |
| if i&1 == 0 { |
| is = append(is, func() int { |
| if i%17 == 15 { |
| i++ |
| } |
| return i |
| }) |
| } |
| } |
| |
| bug := false |
| if sum != 100-10 { |
| println("wrong sum, expected ", 90, ", saw", sum) |
| bug = true |
| } |
| if len(is) != 5 { |
| println("wrong iterations, expected ", 5, ", saw", len(is)) |
| bug = true |
| } |
| sum = 0 |
| for _, f := range is { |
| sum += f() |
| } |
| if sum != 0+2+4+6+8 { |
| println("wrong sum, expected ", 20, ", saw ", sum) |
| bug = true |
| } |
| if bug { |
| panic("for_esc_closure") |
| } |
| } |
| |
| type I int |
| |
| func (x *I) method() int { |
| return int(*x) |
| } |
| |
| func for_esc_method() { |
| // Clone of for_esc_method.go |
| var is []func() int |
| sum := 0 |
| for i := I(0); int(i) < 10; i++ { |
| for j := 0; j < 10; j++ { |
| if int(i) == j { // 10 skips |
| continue |
| } |
| sum++ |
| } |
| if i&1 == 0 { |
| is = append(is, i.method) |
| } |
| } |
| |
| bug := false |
| if sum != 100-10 { |
| println("wrong sum, expected ", 90, ", saw ", sum) |
| bug = true |
| } |
| if len(is) != 5 { |
| println("wrong iterations, expected ", 5, ", saw", len(is)) |
| bug = true |
| } |
| sum = 0 |
| for _, m := range is { |
| sum += m() |
| } |
| if sum != 0+2+4+6+8 { |
| println("wrong sum, expected ", 20, ", saw ", sum) |
| bug = true |
| } |
| if bug { |
| panic("for_esc_method") |
| } |
| } |