mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
780 lines
13 KiB
Go
780 lines
13 KiB
Go
|
|
// errorcheck -0 -d=escapealias=1
|
||
|
|
|
||
|
|
//go:build goexperiment.runtimefreegc
|
||
|
|
|
||
|
|
// Copyright 2025 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.
|
||
|
|
|
||
|
|
// Test recognizing certain patterns of usage,
|
||
|
|
// currently focused on whether a slice is aliased.
|
||
|
|
|
||
|
|
package escapealias
|
||
|
|
|
||
|
|
import "runtime"
|
||
|
|
|
||
|
|
// Basic examples.
|
||
|
|
//
|
||
|
|
// Some of these directly overlap with later tests below, but are presented at the start
|
||
|
|
// to help show the big picture (before going into more variations).
|
||
|
|
|
||
|
|
var alias []int
|
||
|
|
|
||
|
|
func basic1() {
|
||
|
|
// A simple append with no aliasing of s.
|
||
|
|
var s []int
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
_ = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func basic2() []int {
|
||
|
|
// The slice can escape.
|
||
|
|
var s []int
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
return s
|
||
|
|
}
|
||
|
|
|
||
|
|
func basic3() {
|
||
|
|
// A simple example of s being aliased.
|
||
|
|
// We give up when we see the aliasing.
|
||
|
|
var s []int
|
||
|
|
alias = s
|
||
|
|
s = append(s, 0)
|
||
|
|
_ = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func basic4() {
|
||
|
|
// The analysis is conservative, giving up on
|
||
|
|
// IR nodes it doesn't understand. It does not
|
||
|
|
// yet understand comparisons, for example.
|
||
|
|
var s []int
|
||
|
|
_ = s == nil
|
||
|
|
s = append(s, 0)
|
||
|
|
_ = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func basic5() {
|
||
|
|
// We also give up if s is assigned to another variable.
|
||
|
|
var s []int
|
||
|
|
s2 := s
|
||
|
|
s2 = append(s2, 0)
|
||
|
|
_ = s2
|
||
|
|
}
|
||
|
|
|
||
|
|
func basic6() {
|
||
|
|
// A self-assigning append does not create an alias,
|
||
|
|
// so s is still unaliased when we reach the second append here.
|
||
|
|
var s []int
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
_ = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func basic7() {
|
||
|
|
// An append can be unaliased if it happens before aliasing.
|
||
|
|
var s []int
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
alias = s
|
||
|
|
s = append(s, 0)
|
||
|
|
_ = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func basic8() {
|
||
|
|
// Aliasing anywhere in a loop means we give up for the whole loop body,
|
||
|
|
// even if the aliasing is after the append in the loop body.
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
s = append(s, 0)
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
_ = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func basic9() {
|
||
|
|
// Aliases after a loop do not affect whether this is aliasing in the loop.
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
alias = s
|
||
|
|
_ = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func basic10() {
|
||
|
|
// We track the depth at which a slice is declared vs. aliased,
|
||
|
|
// which helps for example with nested loops.
|
||
|
|
// In this example, the aliasing occurs after both loops are done.
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
for range 10 {
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func basic11() {
|
||
|
|
// In contrast, here the aliasing occurs in the outer loop body.
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
for range 10 {
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Some variations on single appends.
|
||
|
|
|
||
|
|
func singleAppend1() []int {
|
||
|
|
var s []int
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
return s
|
||
|
|
}
|
||
|
|
|
||
|
|
func singleAppend2() {
|
||
|
|
var s []int
|
||
|
|
alias = s
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func singleAppend3() {
|
||
|
|
var s []int
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func singleAppend4() {
|
||
|
|
var s []int
|
||
|
|
p := &s
|
||
|
|
_ = p
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func singleAppend5(s []int) {
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func singleAppend6() {
|
||
|
|
var s []int
|
||
|
|
alias, _ = s, 0
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Examples with variations on slice declarations.
|
||
|
|
|
||
|
|
func sliceDeclaration1() {
|
||
|
|
s := []int{}
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
|
||
|
|
func sliceDeclaration2() {
|
||
|
|
s := []int{1, 2, 3}
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
|
||
|
|
func sliceDeclaration3() {
|
||
|
|
s := make([]int, 3)
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
|
||
|
|
func sliceDeclaration4() {
|
||
|
|
s := []int{}
|
||
|
|
alias = s
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func sliceDeclaration5() {
|
||
|
|
s := []int{1, 2, 3}
|
||
|
|
alias = s
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func sliceDeclaration6() {
|
||
|
|
s := make([]int, 3)
|
||
|
|
alias = s
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func sliceDeclaration7() {
|
||
|
|
s, x := []int{}, 0
|
||
|
|
s = append(s, x) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
|
||
|
|
// Basic loops. First, a single loop.
|
||
|
|
|
||
|
|
func loops1a() {
|
||
|
|
var s []int
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops1b() {
|
||
|
|
var s []int
|
||
|
|
for i := range 10 {
|
||
|
|
alias = s
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops1c() {
|
||
|
|
var s []int
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops1d() {
|
||
|
|
var s []int
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops1e() {
|
||
|
|
var s []int
|
||
|
|
for i := range use(s) {
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops1f() {
|
||
|
|
var s []int
|
||
|
|
for i := range use(s) {
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Nested loops with s declared outside the loops.
|
||
|
|
|
||
|
|
func loops2a() {
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops2b() {
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
alias = s
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops2c() {
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops2d() {
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops2e() {
|
||
|
|
var s []int
|
||
|
|
for range use(s) {
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops2f() {
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
for i := range use(s) {
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Nested loops with s declared inside the first loop.
|
||
|
|
|
||
|
|
func loops3a() {
|
||
|
|
for range 10 {
|
||
|
|
var s []int
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops3b() {
|
||
|
|
for range 10 {
|
||
|
|
var s []int
|
||
|
|
for i := range 10 {
|
||
|
|
alias = s
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops3c() {
|
||
|
|
for range 10 {
|
||
|
|
var s []int
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops3d() {
|
||
|
|
for range 10 {
|
||
|
|
var s []int
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops3e() {
|
||
|
|
for range 10 {
|
||
|
|
var s []int
|
||
|
|
for i := range use(s) {
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Loops using OFOR instead of ORANGE.
|
||
|
|
|
||
|
|
func loops4a() {
|
||
|
|
var s []int
|
||
|
|
for i := 0; i < 10; i++ {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops4b() {
|
||
|
|
var s []int
|
||
|
|
for i := 0; i < 10; i++ {
|
||
|
|
alias = s
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops4c() {
|
||
|
|
var s []int
|
||
|
|
for i := 0; i < 10; i++ {
|
||
|
|
s = append(s, i)
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loops4d() {
|
||
|
|
var s []int
|
||
|
|
for i := 0; i < 10; i++ {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
|
||
|
|
// Loops with some initialization variations.
|
||
|
|
|
||
|
|
func loopsInit1() {
|
||
|
|
var i int
|
||
|
|
for s := []int{}; i < 10; i++ {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loopsInit2() {
|
||
|
|
var i int
|
||
|
|
for s := []int{}; i < 10; i++ {
|
||
|
|
s = append(s, i)
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loopsInit3() {
|
||
|
|
var i int
|
||
|
|
for s := []int{}; i < 10; i++ {
|
||
|
|
for range 10 {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loopsInit5() {
|
||
|
|
var i int
|
||
|
|
for s := []int{}; i < 10; i++ {
|
||
|
|
for range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loopsInit5b() {
|
||
|
|
var i int
|
||
|
|
for s := []int{}; i < 10; i++ {
|
||
|
|
for range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loopsInit6() {
|
||
|
|
for range 10 {
|
||
|
|
var i int
|
||
|
|
for s := []int{}; i < 10; i++ {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loopsInit7() {
|
||
|
|
for range 10 {
|
||
|
|
var i int
|
||
|
|
for s := []int{}; i < 10; i++ {
|
||
|
|
s = append(s, i)
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Some initialization variations with use of s in the for or range.
|
||
|
|
|
||
|
|
func loopsInit8() {
|
||
|
|
var s []int
|
||
|
|
for use(s) == 0 {
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loopsInit9() {
|
||
|
|
for s := []int{}; use(s) == 0; {
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loopsInit10() {
|
||
|
|
for s := []int{}; ; use(s) {
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func loopsInit11() {
|
||
|
|
var s [][]int
|
||
|
|
for _, s2 := range s {
|
||
|
|
s = append(s, s2)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Examples of calling functions that get inlined,
|
||
|
|
// starting with a simple pass-through function.
|
||
|
|
|
||
|
|
// TODO(thepudds): we handle many of these starting in https://go.dev/cl/712422
|
||
|
|
|
||
|
|
func inlineReturn(param []int) []int {
|
||
|
|
return param
|
||
|
|
}
|
||
|
|
|
||
|
|
func inline1a() {
|
||
|
|
var s []int
|
||
|
|
s = inlineReturn(s)
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func inline1b() {
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
s = inlineReturn(s)
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func inline1c() {
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
s = inlineReturn(s)
|
||
|
|
alias = s
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func inline1d() {
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
s = inlineReturn(s)
|
||
|
|
s = append(s, 0)
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Examples with an inlined function that uses append.
|
||
|
|
|
||
|
|
func inlineAppend(param []int) []int {
|
||
|
|
param = append(param, 0)
|
||
|
|
// TODO(thepudds): could in theory also handle a direct 'return append(param, 0)'
|
||
|
|
return param
|
||
|
|
}
|
||
|
|
|
||
|
|
func inline2a() {
|
||
|
|
var s []int
|
||
|
|
s = inlineAppend(s)
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func inline2b() {
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
s = inlineAppend(s)
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func inline2c() {
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
s = inlineAppend(s)
|
||
|
|
alias = s
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func inline2d() {
|
||
|
|
var s []int
|
||
|
|
for range 10 {
|
||
|
|
s = inlineAppend(s)
|
||
|
|
s = append(s, 0)
|
||
|
|
alias = s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Examples calling non-inlined functions that do and do not escape.
|
||
|
|
|
||
|
|
var sink interface{}
|
||
|
|
|
||
|
|
//go:noinline
|
||
|
|
func use(s []int) int { return 0 } // s content does not escape
|
||
|
|
|
||
|
|
//go:noinline
|
||
|
|
func escape(s []int) int { sink = s; return 0 } // s content escapes
|
||
|
|
|
||
|
|
func call1() {
|
||
|
|
var s []int
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
use(s)
|
||
|
|
}
|
||
|
|
|
||
|
|
// TODO(thepudds): OK to disallow this for now, but would be nice to allow this given use(s) is non-escaping.
|
||
|
|
func call2() {
|
||
|
|
var s []int
|
||
|
|
use(s)
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func call3() {
|
||
|
|
var s []int
|
||
|
|
s = append(s, use(s))
|
||
|
|
}
|
||
|
|
|
||
|
|
func call4() {
|
||
|
|
var s []int
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
use(s)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func callEscape1() {
|
||
|
|
var s []int
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
escape(s)
|
||
|
|
}
|
||
|
|
|
||
|
|
func callEscape2() {
|
||
|
|
var s []int
|
||
|
|
escape(s)
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func callEscape3() {
|
||
|
|
var s []int
|
||
|
|
s = append(s, escape(s))
|
||
|
|
}
|
||
|
|
|
||
|
|
func callEscape4() {
|
||
|
|
var s []int
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
escape(s)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Examples of some additional expressions we understand.
|
||
|
|
|
||
|
|
func expr1() {
|
||
|
|
var s []int
|
||
|
|
_ = len(s)
|
||
|
|
_ = cap(s)
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
|
||
|
|
// Examples of some expressions or statements we do not understand.
|
||
|
|
// Some of these we could handle in the future, but some likely not.
|
||
|
|
|
||
|
|
func notUnderstood1() {
|
||
|
|
var s []int
|
||
|
|
s = append(s[:], 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func notUnderstood2() {
|
||
|
|
// Note: we must be careful if we analyze slice expressions.
|
||
|
|
// See related comment about slice expressions in (*aliasAnalysis).analyze.
|
||
|
|
var s []int
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
s = s[1:] // s no longer points to the base of the heap object.
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func notUnderstood3() {
|
||
|
|
// The first append is currently the heart of slices.Grow.
|
||
|
|
var s []int
|
||
|
|
n := 1000
|
||
|
|
s = append(s[:cap(s)], make([]int, n)...)[:len(s)]
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
func notUnderstood4() []int {
|
||
|
|
// A return statement could be allowed to use the slice in a loop
|
||
|
|
// because we cannot revisit the append once we return.
|
||
|
|
var s []int
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, 0)
|
||
|
|
if i > 5 {
|
||
|
|
return s
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return s
|
||
|
|
}
|
||
|
|
|
||
|
|
func notUnderstood5() {
|
||
|
|
// AddCleanup is an example function call that we do not understand.
|
||
|
|
// See related comment about specials in (*aliasAnalysis).analyze.
|
||
|
|
var s []int
|
||
|
|
runtime.AddCleanup(&s, func(int) {}, 0)
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Examples with closures.
|
||
|
|
|
||
|
|
func closure1() {
|
||
|
|
var s []int // declared outside the closure
|
||
|
|
f := func() {
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
_ = f // avoid calling f, which would just get inlined
|
||
|
|
}
|
||
|
|
|
||
|
|
// TODO(thepudds): it's probably ok that we currently allow this. Could conservatively
|
||
|
|
// disallow if needed.
|
||
|
|
func closure2() {
|
||
|
|
f := func() {
|
||
|
|
var s []int // declared inside the closure
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i) // ERROR "append using non-aliased slice"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
_ = f // avoid calling f, which would just get inlined
|
||
|
|
}
|
||
|
|
|
||
|
|
// Examples with goto and labels.
|
||
|
|
|
||
|
|
func goto1() {
|
||
|
|
var s []int
|
||
|
|
label:
|
||
|
|
s = append(s, 0)
|
||
|
|
alias = s
|
||
|
|
goto label
|
||
|
|
}
|
||
|
|
|
||
|
|
func goto2() {
|
||
|
|
var s []int
|
||
|
|
s = append(s, 0) // ERROR "append using non-aliased slice"
|
||
|
|
alias = s
|
||
|
|
label:
|
||
|
|
goto label
|
||
|
|
}
|
||
|
|
|
||
|
|
func goto3() {
|
||
|
|
var s []int
|
||
|
|
label:
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
}
|
||
|
|
goto label
|
||
|
|
}
|
||
|
|
|
||
|
|
func break1() {
|
||
|
|
var s []int
|
||
|
|
label:
|
||
|
|
for i := range 10 {
|
||
|
|
s = append(s, i)
|
||
|
|
break label
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Examples with iterators.
|
||
|
|
|
||
|
|
func collect[E any](seq Seq[E]) []E {
|
||
|
|
var result []E
|
||
|
|
for v := range seq {
|
||
|
|
result = append(result, v)
|
||
|
|
}
|
||
|
|
return result
|
||
|
|
}
|
||
|
|
|
||
|
|
func count(yield func(int) bool) {
|
||
|
|
for i := range 10 {
|
||
|
|
if !yield(i) {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func iteratorUse1() {
|
||
|
|
var s []int
|
||
|
|
s = collect(count)
|
||
|
|
_ = s
|
||
|
|
}
|
||
|
|
|
||
|
|
func iteratorUse2() {
|
||
|
|
var s []int
|
||
|
|
s = collect(count)
|
||
|
|
s = append(s, 0)
|
||
|
|
}
|
||
|
|
|
||
|
|
type Seq[E any] func(yield func(E) bool)
|