mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: for rangefunc, add checks and tests, fix panic interactions
Modify rangefunc #next protocol to make it more robust Extra-terrible nests of rangefunc iterators caused the prior implementation to misbehave non-locally (in outer loops). Add more rangefunc exit flag tests, parallel and tricky This tests the assertion that a rangefunc iterator running in parallel can trigger the race detector if any of the parallel goroutines attempts an early exit. It also verifies that if everything else is carefully written, that it does NOT trigger the race detector if all the parts run time completion. Another test tries to rerun a yield function within a loop, so that any per-line shared checking would be fooled. Added all the use-of-body/yield-function checking. These checks handle pathological cases that would cause rangefunc for loops to behave in surprising ways (compared to "regular" for loops). For example, a rangefunc iterator might defer-recover a panic thrown in the syntactic body of a loop; this notices the fault and panics with an explanation Modified closure naming to ID rangefunc bodies Add a "-range<N>" suffix to the name of any closure generated for a rangefunc loop body, as provided in Alessandro Arzilli's CL (which is merged into this one). Fix return values for panicky range functions This removes the delayed implementation of "return x" by ensuring that return values (in rangefunc-return-containing functions) always have names and translating the "return x" into "#rv1 = x" where #rv1 is the synthesized name of the first result. Updates #61405. Change-Id: I933299ecce04ceabcf1c0c2de8e610b2ecd1cfd8 Reviewed-on: https://go-review.googlesource.com/c/go/+/584596 Reviewed-by: Matthew Dempsky <mdempsky@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Tim King <taking@google.com>
This commit is contained in:
parent
643865856c
commit
5a9dabc2ba
16 changed files with 1721 additions and 570 deletions
|
|
@ -508,7 +508,7 @@ opSwitch:
|
|||
case "throw":
|
||||
v.budget -= inlineExtraThrowCost
|
||||
break opSwitch
|
||||
case "panicrangeexit":
|
||||
case "panicrangestate":
|
||||
cheap = true
|
||||
}
|
||||
// Special case for reflect.noescape. It does just type
|
||||
|
|
|
|||
|
|
@ -90,14 +90,18 @@ type Func struct {
|
|||
|
||||
Inl *Inline
|
||||
|
||||
// funcLitGen and goDeferGen track how many closures have been
|
||||
// created in this function for function literals and go/defer
|
||||
// wrappers, respectively. Used by closureName for creating unique
|
||||
// function names.
|
||||
//
|
||||
// RangeParent, if non-nil, is the first non-range body function containing
|
||||
// the closure for the body of a range function.
|
||||
RangeParent *Func
|
||||
|
||||
// funcLitGen, rangeLitGen and goDeferGen track how many closures have been
|
||||
// created in this function for function literals, range-over-func loops,
|
||||
// and go/defer wrappers, respectively. Used by closureName for creating
|
||||
// unique function names.
|
||||
// Tracking goDeferGen separately avoids wrappers throwing off
|
||||
// function literal numbering (e.g., runtime/trace_test.TestTraceSymbolize.func11).
|
||||
funcLitGen int32
|
||||
rangeLitGen int32
|
||||
goDeferGen int32
|
||||
|
||||
Label int32 // largest auto-generated label in this function
|
||||
|
|
@ -417,20 +421,25 @@ var globClosgen int32
|
|||
|
||||
// closureName generates a new unique name for a closure within outerfn at pos.
|
||||
func closureName(outerfn *Func, pos src.XPos, why Op) *types.Sym {
|
||||
if outerfn != nil && outerfn.OClosure != nil && outerfn.OClosure.Func.RangeParent != nil {
|
||||
outerfn = outerfn.OClosure.Func.RangeParent
|
||||
}
|
||||
pkg := types.LocalPkg
|
||||
outer := "glob."
|
||||
var prefix string
|
||||
var prefix string = "."
|
||||
switch why {
|
||||
default:
|
||||
base.FatalfAt(pos, "closureName: bad Op: %v", why)
|
||||
case OCLOSURE:
|
||||
if outerfn == nil || outerfn.OClosure == nil {
|
||||
prefix = "func"
|
||||
prefix = ".func"
|
||||
}
|
||||
case ORANGE:
|
||||
prefix = "-range"
|
||||
case OGO:
|
||||
prefix = "gowrap"
|
||||
prefix = ".gowrap"
|
||||
case ODEFER:
|
||||
prefix = "deferwrap"
|
||||
prefix = ".deferwrap"
|
||||
}
|
||||
gen := &globClosgen
|
||||
|
||||
|
|
@ -441,9 +450,12 @@ func closureName(outerfn *Func, pos src.XPos, why Op) *types.Sym {
|
|||
pkg = outerfn.Sym().Pkg
|
||||
outer = FuncName(outerfn)
|
||||
|
||||
if why == OCLOSURE {
|
||||
switch why {
|
||||
case OCLOSURE:
|
||||
gen = &outerfn.funcLitGen
|
||||
} else {
|
||||
case ORANGE:
|
||||
gen = &outerfn.rangeLitGen
|
||||
default:
|
||||
gen = &outerfn.goDeferGen
|
||||
}
|
||||
}
|
||||
|
|
@ -460,7 +472,7 @@ func closureName(outerfn *Func, pos src.XPos, why Op) *types.Sym {
|
|||
}
|
||||
|
||||
*gen++
|
||||
return pkg.Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
|
||||
return pkg.Lookup(fmt.Sprintf("%s%s%d", outer, prefix, *gen))
|
||||
}
|
||||
|
||||
// NewClosureFunc creates a new Func to represent a function literal
|
||||
|
|
@ -490,6 +502,12 @@ func NewClosureFunc(fpos, cpos src.XPos, why Op, typ *types.Type, outerfn *Func,
|
|||
clo.pos = cpos
|
||||
clo.SetType(typ)
|
||||
clo.SetTypecheck(1)
|
||||
if why == ORANGE {
|
||||
clo.Func.RangeParent = outerfn
|
||||
if outerfn.OClosure != nil && outerfn.OClosure.Func.RangeParent != nil {
|
||||
clo.Func.RangeParent = outerfn.OClosure.Func.RangeParent
|
||||
}
|
||||
}
|
||||
fn.OClosure = clo
|
||||
|
||||
fn.Nname.Defn = fn
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func TestSizeof(t *testing.T) {
|
|||
_32bit uintptr // size on 32bit platforms
|
||||
_64bit uintptr // size on 64bit platforms
|
||||
}{
|
||||
{Func{}, 168, 288},
|
||||
{Func{}, 176, 296},
|
||||
{Name{}, 96, 168},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ var versionErrorRx = regexp.MustCompile(`requires go[0-9]+\.[0-9]+ or later`)
|
|||
|
||||
// checkFiles configures and runs the types2 checker on the given
|
||||
// parsed source files and then returns the result.
|
||||
func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info) {
|
||||
// The map result value indicates which closures are generated from the bodies of range function loops.
|
||||
func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info, map[*syntax.FuncLit]bool) {
|
||||
if base.SyntaxErrors() != 0 {
|
||||
base.ErrorExit()
|
||||
}
|
||||
|
|
@ -150,9 +151,9 @@ func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info) {
|
|||
// If we do the rewrite in the back end, like between typecheck and walk,
|
||||
// then the new implicit closure will not have a unified IR inline body,
|
||||
// and bodyReaderFor will fail.
|
||||
rangefunc.Rewrite(pkg, info, files)
|
||||
rangeInfo := rangefunc.Rewrite(pkg, info, files)
|
||||
|
||||
return pkg, info
|
||||
return pkg, info, rangeInfo
|
||||
}
|
||||
|
||||
// A cycleFinder detects anonymous interface cycles (go.dev/issue/56103).
|
||||
|
|
|
|||
|
|
@ -2704,7 +2704,7 @@ func (r *reader) syntheticClosure(origPos src.XPos, typ *types.Type, ifaceHack b
|
|||
return false
|
||||
}
|
||||
|
||||
fn := r.inlClosureFunc(origPos, typ)
|
||||
fn := r.inlClosureFunc(origPos, typ, ir.OCLOSURE)
|
||||
fn.SetWrapper(true)
|
||||
|
||||
clo := fn.OClosure
|
||||
|
|
@ -3035,8 +3035,12 @@ func (r *reader) funcLit() ir.Node {
|
|||
origPos := r.pos()
|
||||
sig := r.signature(nil)
|
||||
r.suppressInlPos--
|
||||
why := ir.OCLOSURE
|
||||
if r.Bool() {
|
||||
why = ir.ORANGE
|
||||
}
|
||||
|
||||
fn := r.inlClosureFunc(origPos, sig)
|
||||
fn := r.inlClosureFunc(origPos, sig, why)
|
||||
|
||||
fn.ClosureVars = make([]*ir.Name, 0, r.Len())
|
||||
for len(fn.ClosureVars) < cap(fn.ClosureVars) {
|
||||
|
|
@ -3062,14 +3066,14 @@ func (r *reader) funcLit() ir.Node {
|
|||
|
||||
// inlClosureFunc constructs a new closure function, but correctly
|
||||
// handles inlining.
|
||||
func (r *reader) inlClosureFunc(origPos src.XPos, sig *types.Type) *ir.Func {
|
||||
func (r *reader) inlClosureFunc(origPos src.XPos, sig *types.Type, why ir.Op) *ir.Func {
|
||||
curfn := r.inlCaller
|
||||
if curfn == nil {
|
||||
curfn = r.curfn
|
||||
}
|
||||
|
||||
// TODO(mdempsky): Remove hard-coding of typecheck.Target.
|
||||
return ir.NewClosureFunc(origPos, r.inlPos(origPos), ir.OCLOSURE, sig, curfn, typecheck.Target)
|
||||
return ir.NewClosureFunc(origPos, r.inlPos(origPos), why, sig, curfn, typecheck.Target)
|
||||
}
|
||||
|
||||
func (r *reader) exprList() []ir.Node {
|
||||
|
|
|
|||
|
|
@ -304,9 +304,9 @@ func readBodies(target *ir.Package, duringInlining bool) {
|
|||
// writes an export data package stub representing them,
|
||||
// and returns the result.
|
||||
func writePkgStub(m posMap, noders []*noder) string {
|
||||
pkg, info := checkFiles(m, noders)
|
||||
pkg, info, otherInfo := checkFiles(m, noders)
|
||||
|
||||
pw := newPkgWriter(m, pkg, info)
|
||||
pw := newPkgWriter(m, pkg, info, otherInfo)
|
||||
|
||||
pw.collectDecls(noders)
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ type pkgWriter struct {
|
|||
m posMap
|
||||
curpkg *types2.Package
|
||||
info *types2.Info
|
||||
rangeFuncBodyClosures map[*syntax.FuncLit]bool // non-public information, e.g., which functions are closures range function bodies?
|
||||
|
||||
// Indices for previously written syntax and types2 things.
|
||||
|
||||
|
|
@ -90,13 +91,14 @@ type pkgWriter struct {
|
|||
|
||||
// newPkgWriter returns an initialized pkgWriter for the specified
|
||||
// package.
|
||||
func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info) *pkgWriter {
|
||||
func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info, otherInfo map[*syntax.FuncLit]bool) *pkgWriter {
|
||||
return &pkgWriter{
|
||||
PkgEncoder: pkgbits.NewPkgEncoder(base.Debug.SyncFrames),
|
||||
|
||||
m: m,
|
||||
curpkg: pkg,
|
||||
info: info,
|
||||
rangeFuncBodyClosures: otherInfo,
|
||||
|
||||
pkgsIdx: make(map[*types2.Package]pkgbits.Index),
|
||||
objsIdx: make(map[types2.Object]pkgbits.Index),
|
||||
|
|
@ -2336,6 +2338,7 @@ func (w *writer) funcLit(expr *syntax.FuncLit) {
|
|||
w.Sync(pkgbits.SyncFuncLit)
|
||||
w.pos(expr)
|
||||
w.signature(sig)
|
||||
w.Bool(w.p.rangeFuncBodyClosures[expr])
|
||||
|
||||
w.Len(len(closureVars))
|
||||
for _, cv := range closureVars {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1461,7 +1461,11 @@ func (s *state) stmt(n ir.Node) {
|
|||
s.callResult(n, callNormal)
|
||||
if n.Op() == ir.OCALLFUNC && n.Fun.Op() == ir.ONAME && n.Fun.(*ir.Name).Class == ir.PFUNC {
|
||||
if fn := n.Fun.Sym().Name; base.Flag.CompilingRuntime && fn == "throw" ||
|
||||
n.Fun.Sym().Pkg == ir.Pkgs.Runtime && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap" || fn == "panicunsafeslicelen" || fn == "panicunsafeslicenilptr" || fn == "panicunsafestringlen" || fn == "panicunsafestringnilptr") {
|
||||
n.Fun.Sym().Pkg == ir.Pkgs.Runtime &&
|
||||
(fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" ||
|
||||
fn == "panicmakeslicelen" || fn == "panicmakeslicecap" || fn == "panicunsafeslicelen" ||
|
||||
fn == "panicunsafeslicenilptr" || fn == "panicunsafestringlen" || fn == "panicunsafestringnilptr" ||
|
||||
fn == "panicrangestate") {
|
||||
m := s.mem()
|
||||
b := s.endBlock()
|
||||
b.Kind = ssa.BlockExit
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ func interfaceSwitch(s *byte, t *byte) (int, *byte)
|
|||
func ifaceeq(tab *uintptr, x, y unsafe.Pointer) (ret bool)
|
||||
func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool)
|
||||
|
||||
// panic for iteration after exit in range func
|
||||
func panicrangeexit()
|
||||
// panic for various rangefunc iterator errors
|
||||
func panicrangestate(state int)
|
||||
|
||||
// defer in range over func
|
||||
func deferrangefunc() interface{}
|
||||
|
|
|
|||
|
|
@ -102,142 +102,142 @@ var runtimeDecls = [...]struct {
|
|||
{"interfaceSwitch", funcTag, 70},
|
||||
{"ifaceeq", funcTag, 72},
|
||||
{"efaceeq", funcTag, 72},
|
||||
{"panicrangeexit", funcTag, 9},
|
||||
{"deferrangefunc", funcTag, 73},
|
||||
{"rand32", funcTag, 74},
|
||||
{"makemap64", funcTag, 76},
|
||||
{"makemap", funcTag, 77},
|
||||
{"makemap_small", funcTag, 78},
|
||||
{"mapaccess1", funcTag, 79},
|
||||
{"mapaccess1_fast32", funcTag, 80},
|
||||
{"mapaccess1_fast64", funcTag, 81},
|
||||
{"mapaccess1_faststr", funcTag, 82},
|
||||
{"mapaccess1_fat", funcTag, 83},
|
||||
{"mapaccess2", funcTag, 84},
|
||||
{"mapaccess2_fast32", funcTag, 85},
|
||||
{"mapaccess2_fast64", funcTag, 86},
|
||||
{"mapaccess2_faststr", funcTag, 87},
|
||||
{"mapaccess2_fat", funcTag, 88},
|
||||
{"mapassign", funcTag, 79},
|
||||
{"mapassign_fast32", funcTag, 80},
|
||||
{"mapassign_fast32ptr", funcTag, 89},
|
||||
{"mapassign_fast64", funcTag, 81},
|
||||
{"mapassign_fast64ptr", funcTag, 89},
|
||||
{"mapassign_faststr", funcTag, 82},
|
||||
{"mapiterinit", funcTag, 90},
|
||||
{"mapdelete", funcTag, 90},
|
||||
{"mapdelete_fast32", funcTag, 91},
|
||||
{"mapdelete_fast64", funcTag, 92},
|
||||
{"mapdelete_faststr", funcTag, 93},
|
||||
{"mapiternext", funcTag, 94},
|
||||
{"mapclear", funcTag, 95},
|
||||
{"makechan64", funcTag, 97},
|
||||
{"makechan", funcTag, 98},
|
||||
{"chanrecv1", funcTag, 100},
|
||||
{"chanrecv2", funcTag, 101},
|
||||
{"chansend1", funcTag, 103},
|
||||
{"closechan", funcTag, 104},
|
||||
{"chanlen", funcTag, 105},
|
||||
{"chancap", funcTag, 105},
|
||||
{"writeBarrier", varTag, 107},
|
||||
{"typedmemmove", funcTag, 108},
|
||||
{"typedmemclr", funcTag, 109},
|
||||
{"typedslicecopy", funcTag, 110},
|
||||
{"selectnbsend", funcTag, 111},
|
||||
{"selectnbrecv", funcTag, 112},
|
||||
{"selectsetpc", funcTag, 113},
|
||||
{"selectgo", funcTag, 114},
|
||||
{"panicrangestate", funcTag, 73},
|
||||
{"deferrangefunc", funcTag, 74},
|
||||
{"rand32", funcTag, 75},
|
||||
{"makemap64", funcTag, 77},
|
||||
{"makemap", funcTag, 78},
|
||||
{"makemap_small", funcTag, 79},
|
||||
{"mapaccess1", funcTag, 80},
|
||||
{"mapaccess1_fast32", funcTag, 81},
|
||||
{"mapaccess1_fast64", funcTag, 82},
|
||||
{"mapaccess1_faststr", funcTag, 83},
|
||||
{"mapaccess1_fat", funcTag, 84},
|
||||
{"mapaccess2", funcTag, 85},
|
||||
{"mapaccess2_fast32", funcTag, 86},
|
||||
{"mapaccess2_fast64", funcTag, 87},
|
||||
{"mapaccess2_faststr", funcTag, 88},
|
||||
{"mapaccess2_fat", funcTag, 89},
|
||||
{"mapassign", funcTag, 80},
|
||||
{"mapassign_fast32", funcTag, 81},
|
||||
{"mapassign_fast32ptr", funcTag, 90},
|
||||
{"mapassign_fast64", funcTag, 82},
|
||||
{"mapassign_fast64ptr", funcTag, 90},
|
||||
{"mapassign_faststr", funcTag, 83},
|
||||
{"mapiterinit", funcTag, 91},
|
||||
{"mapdelete", funcTag, 91},
|
||||
{"mapdelete_fast32", funcTag, 92},
|
||||
{"mapdelete_fast64", funcTag, 93},
|
||||
{"mapdelete_faststr", funcTag, 94},
|
||||
{"mapiternext", funcTag, 95},
|
||||
{"mapclear", funcTag, 96},
|
||||
{"makechan64", funcTag, 98},
|
||||
{"makechan", funcTag, 99},
|
||||
{"chanrecv1", funcTag, 101},
|
||||
{"chanrecv2", funcTag, 102},
|
||||
{"chansend1", funcTag, 104},
|
||||
{"closechan", funcTag, 105},
|
||||
{"chanlen", funcTag, 106},
|
||||
{"chancap", funcTag, 106},
|
||||
{"writeBarrier", varTag, 108},
|
||||
{"typedmemmove", funcTag, 109},
|
||||
{"typedmemclr", funcTag, 110},
|
||||
{"typedslicecopy", funcTag, 111},
|
||||
{"selectnbsend", funcTag, 112},
|
||||
{"selectnbrecv", funcTag, 113},
|
||||
{"selectsetpc", funcTag, 114},
|
||||
{"selectgo", funcTag, 115},
|
||||
{"block", funcTag, 9},
|
||||
{"makeslice", funcTag, 115},
|
||||
{"makeslice64", funcTag, 116},
|
||||
{"makeslicecopy", funcTag, 117},
|
||||
{"growslice", funcTag, 119},
|
||||
{"unsafeslicecheckptr", funcTag, 120},
|
||||
{"makeslice", funcTag, 116},
|
||||
{"makeslice64", funcTag, 117},
|
||||
{"makeslicecopy", funcTag, 118},
|
||||
{"growslice", funcTag, 120},
|
||||
{"unsafeslicecheckptr", funcTag, 121},
|
||||
{"panicunsafeslicelen", funcTag, 9},
|
||||
{"panicunsafeslicenilptr", funcTag, 9},
|
||||
{"unsafestringcheckptr", funcTag, 121},
|
||||
{"unsafestringcheckptr", funcTag, 122},
|
||||
{"panicunsafestringlen", funcTag, 9},
|
||||
{"panicunsafestringnilptr", funcTag, 9},
|
||||
{"memmove", funcTag, 122},
|
||||
{"memclrNoHeapPointers", funcTag, 123},
|
||||
{"memclrHasPointers", funcTag, 123},
|
||||
{"memequal", funcTag, 124},
|
||||
{"memequal0", funcTag, 125},
|
||||
{"memequal8", funcTag, 125},
|
||||
{"memequal16", funcTag, 125},
|
||||
{"memequal32", funcTag, 125},
|
||||
{"memequal64", funcTag, 125},
|
||||
{"memequal128", funcTag, 125},
|
||||
{"f32equal", funcTag, 126},
|
||||
{"f64equal", funcTag, 126},
|
||||
{"c64equal", funcTag, 126},
|
||||
{"c128equal", funcTag, 126},
|
||||
{"strequal", funcTag, 126},
|
||||
{"interequal", funcTag, 126},
|
||||
{"nilinterequal", funcTag, 126},
|
||||
{"memhash", funcTag, 127},
|
||||
{"memhash0", funcTag, 128},
|
||||
{"memhash8", funcTag, 128},
|
||||
{"memhash16", funcTag, 128},
|
||||
{"memhash32", funcTag, 128},
|
||||
{"memhash64", funcTag, 128},
|
||||
{"memhash128", funcTag, 128},
|
||||
{"f32hash", funcTag, 129},
|
||||
{"f64hash", funcTag, 129},
|
||||
{"c64hash", funcTag, 129},
|
||||
{"c128hash", funcTag, 129},
|
||||
{"strhash", funcTag, 129},
|
||||
{"interhash", funcTag, 129},
|
||||
{"nilinterhash", funcTag, 129},
|
||||
{"int64div", funcTag, 130},
|
||||
{"uint64div", funcTag, 131},
|
||||
{"int64mod", funcTag, 130},
|
||||
{"uint64mod", funcTag, 131},
|
||||
{"float64toint64", funcTag, 132},
|
||||
{"float64touint64", funcTag, 133},
|
||||
{"float64touint32", funcTag, 134},
|
||||
{"int64tofloat64", funcTag, 135},
|
||||
{"int64tofloat32", funcTag, 137},
|
||||
{"uint64tofloat64", funcTag, 138},
|
||||
{"uint64tofloat32", funcTag, 139},
|
||||
{"uint32tofloat64", funcTag, 140},
|
||||
{"complex128div", funcTag, 141},
|
||||
{"getcallerpc", funcTag, 142},
|
||||
{"getcallersp", funcTag, 142},
|
||||
{"memmove", funcTag, 123},
|
||||
{"memclrNoHeapPointers", funcTag, 124},
|
||||
{"memclrHasPointers", funcTag, 124},
|
||||
{"memequal", funcTag, 125},
|
||||
{"memequal0", funcTag, 126},
|
||||
{"memequal8", funcTag, 126},
|
||||
{"memequal16", funcTag, 126},
|
||||
{"memequal32", funcTag, 126},
|
||||
{"memequal64", funcTag, 126},
|
||||
{"memequal128", funcTag, 126},
|
||||
{"f32equal", funcTag, 127},
|
||||
{"f64equal", funcTag, 127},
|
||||
{"c64equal", funcTag, 127},
|
||||
{"c128equal", funcTag, 127},
|
||||
{"strequal", funcTag, 127},
|
||||
{"interequal", funcTag, 127},
|
||||
{"nilinterequal", funcTag, 127},
|
||||
{"memhash", funcTag, 128},
|
||||
{"memhash0", funcTag, 129},
|
||||
{"memhash8", funcTag, 129},
|
||||
{"memhash16", funcTag, 129},
|
||||
{"memhash32", funcTag, 129},
|
||||
{"memhash64", funcTag, 129},
|
||||
{"memhash128", funcTag, 129},
|
||||
{"f32hash", funcTag, 130},
|
||||
{"f64hash", funcTag, 130},
|
||||
{"c64hash", funcTag, 130},
|
||||
{"c128hash", funcTag, 130},
|
||||
{"strhash", funcTag, 130},
|
||||
{"interhash", funcTag, 130},
|
||||
{"nilinterhash", funcTag, 130},
|
||||
{"int64div", funcTag, 131},
|
||||
{"uint64div", funcTag, 132},
|
||||
{"int64mod", funcTag, 131},
|
||||
{"uint64mod", funcTag, 132},
|
||||
{"float64toint64", funcTag, 133},
|
||||
{"float64touint64", funcTag, 134},
|
||||
{"float64touint32", funcTag, 135},
|
||||
{"int64tofloat64", funcTag, 136},
|
||||
{"int64tofloat32", funcTag, 138},
|
||||
{"uint64tofloat64", funcTag, 139},
|
||||
{"uint64tofloat32", funcTag, 140},
|
||||
{"uint32tofloat64", funcTag, 141},
|
||||
{"complex128div", funcTag, 142},
|
||||
{"getcallerpc", funcTag, 143},
|
||||
{"getcallersp", funcTag, 143},
|
||||
{"racefuncenter", funcTag, 31},
|
||||
{"racefuncexit", funcTag, 9},
|
||||
{"raceread", funcTag, 31},
|
||||
{"racewrite", funcTag, 31},
|
||||
{"racereadrange", funcTag, 143},
|
||||
{"racewriterange", funcTag, 143},
|
||||
{"msanread", funcTag, 143},
|
||||
{"msanwrite", funcTag, 143},
|
||||
{"msanmove", funcTag, 144},
|
||||
{"asanread", funcTag, 143},
|
||||
{"asanwrite", funcTag, 143},
|
||||
{"checkptrAlignment", funcTag, 145},
|
||||
{"checkptrArithmetic", funcTag, 147},
|
||||
{"libfuzzerTraceCmp1", funcTag, 148},
|
||||
{"libfuzzerTraceCmp2", funcTag, 149},
|
||||
{"libfuzzerTraceCmp4", funcTag, 150},
|
||||
{"libfuzzerTraceCmp8", funcTag, 151},
|
||||
{"libfuzzerTraceConstCmp1", funcTag, 148},
|
||||
{"libfuzzerTraceConstCmp2", funcTag, 149},
|
||||
{"libfuzzerTraceConstCmp4", funcTag, 150},
|
||||
{"libfuzzerTraceConstCmp8", funcTag, 151},
|
||||
{"libfuzzerHookStrCmp", funcTag, 152},
|
||||
{"libfuzzerHookEqualFold", funcTag, 152},
|
||||
{"addCovMeta", funcTag, 154},
|
||||
{"racereadrange", funcTag, 144},
|
||||
{"racewriterange", funcTag, 144},
|
||||
{"msanread", funcTag, 144},
|
||||
{"msanwrite", funcTag, 144},
|
||||
{"msanmove", funcTag, 145},
|
||||
{"asanread", funcTag, 144},
|
||||
{"asanwrite", funcTag, 144},
|
||||
{"checkptrAlignment", funcTag, 146},
|
||||
{"checkptrArithmetic", funcTag, 148},
|
||||
{"libfuzzerTraceCmp1", funcTag, 149},
|
||||
{"libfuzzerTraceCmp2", funcTag, 150},
|
||||
{"libfuzzerTraceCmp4", funcTag, 151},
|
||||
{"libfuzzerTraceCmp8", funcTag, 152},
|
||||
{"libfuzzerTraceConstCmp1", funcTag, 149},
|
||||
{"libfuzzerTraceConstCmp2", funcTag, 150},
|
||||
{"libfuzzerTraceConstCmp4", funcTag, 151},
|
||||
{"libfuzzerTraceConstCmp8", funcTag, 152},
|
||||
{"libfuzzerHookStrCmp", funcTag, 153},
|
||||
{"libfuzzerHookEqualFold", funcTag, 153},
|
||||
{"addCovMeta", funcTag, 155},
|
||||
{"x86HasPOPCNT", varTag, 6},
|
||||
{"x86HasSSE41", varTag, 6},
|
||||
{"x86HasFMA", varTag, 6},
|
||||
{"armHasVFPv4", varTag, 6},
|
||||
{"arm64HasATOMICS", varTag, 6},
|
||||
{"asanregisterglobals", funcTag, 123},
|
||||
{"asanregisterglobals", funcTag, 124},
|
||||
}
|
||||
|
||||
func runtimeTypes() []*types.Type {
|
||||
var typs [155]*types.Type
|
||||
var typs [156]*types.Type
|
||||
typs[0] = types.ByteType
|
||||
typs[1] = types.NewPtr(typs[0])
|
||||
typs[2] = types.Types[types.TANY]
|
||||
|
|
@ -311,88 +311,89 @@ func runtimeTypes() []*types.Type {
|
|||
typs[70] = newSig(params(typs[1], typs[1]), params(typs[15], typs[1]))
|
||||
typs[71] = types.NewPtr(typs[5])
|
||||
typs[72] = newSig(params(typs[71], typs[7], typs[7]), params(typs[6]))
|
||||
typs[73] = newSig(nil, params(typs[10]))
|
||||
typs[74] = newSig(nil, params(typs[60]))
|
||||
typs[75] = types.NewMap(typs[2], typs[2])
|
||||
typs[76] = newSig(params(typs[1], typs[22], typs[3]), params(typs[75]))
|
||||
typs[77] = newSig(params(typs[1], typs[15], typs[3]), params(typs[75]))
|
||||
typs[78] = newSig(nil, params(typs[75]))
|
||||
typs[79] = newSig(params(typs[1], typs[75], typs[3]), params(typs[3]))
|
||||
typs[80] = newSig(params(typs[1], typs[75], typs[60]), params(typs[3]))
|
||||
typs[81] = newSig(params(typs[1], typs[75], typs[24]), params(typs[3]))
|
||||
typs[82] = newSig(params(typs[1], typs[75], typs[28]), params(typs[3]))
|
||||
typs[83] = newSig(params(typs[1], typs[75], typs[3], typs[1]), params(typs[3]))
|
||||
typs[84] = newSig(params(typs[1], typs[75], typs[3]), params(typs[3], typs[6]))
|
||||
typs[85] = newSig(params(typs[1], typs[75], typs[60]), params(typs[3], typs[6]))
|
||||
typs[86] = newSig(params(typs[1], typs[75], typs[24]), params(typs[3], typs[6]))
|
||||
typs[87] = newSig(params(typs[1], typs[75], typs[28]), params(typs[3], typs[6]))
|
||||
typs[88] = newSig(params(typs[1], typs[75], typs[3], typs[1]), params(typs[3], typs[6]))
|
||||
typs[89] = newSig(params(typs[1], typs[75], typs[7]), params(typs[3]))
|
||||
typs[90] = newSig(params(typs[1], typs[75], typs[3]), nil)
|
||||
typs[91] = newSig(params(typs[1], typs[75], typs[60]), nil)
|
||||
typs[92] = newSig(params(typs[1], typs[75], typs[24]), nil)
|
||||
typs[93] = newSig(params(typs[1], typs[75], typs[28]), nil)
|
||||
typs[94] = newSig(params(typs[3]), nil)
|
||||
typs[95] = newSig(params(typs[1], typs[75]), nil)
|
||||
typs[96] = types.NewChan(typs[2], types.Cboth)
|
||||
typs[97] = newSig(params(typs[1], typs[22]), params(typs[96]))
|
||||
typs[98] = newSig(params(typs[1], typs[15]), params(typs[96]))
|
||||
typs[99] = types.NewChan(typs[2], types.Crecv)
|
||||
typs[100] = newSig(params(typs[99], typs[3]), nil)
|
||||
typs[101] = newSig(params(typs[99], typs[3]), params(typs[6]))
|
||||
typs[102] = types.NewChan(typs[2], types.Csend)
|
||||
typs[103] = newSig(params(typs[102], typs[3]), nil)
|
||||
typs[104] = newSig(params(typs[102]), nil)
|
||||
typs[105] = newSig(params(typs[2]), params(typs[15]))
|
||||
typs[106] = types.NewArray(typs[0], 3)
|
||||
typs[107] = types.NewStruct([]*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[106]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])})
|
||||
typs[108] = newSig(params(typs[1], typs[3], typs[3]), nil)
|
||||
typs[109] = newSig(params(typs[1], typs[3]), nil)
|
||||
typs[110] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15]))
|
||||
typs[111] = newSig(params(typs[102], typs[3]), params(typs[6]))
|
||||
typs[112] = newSig(params(typs[3], typs[99]), params(typs[6], typs[6]))
|
||||
typs[113] = newSig(params(typs[71]), nil)
|
||||
typs[114] = newSig(params(typs[1], typs[1], typs[71], typs[15], typs[15], typs[6]), params(typs[15], typs[6]))
|
||||
typs[115] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7]))
|
||||
typs[116] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7]))
|
||||
typs[117] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7]))
|
||||
typs[118] = types.NewSlice(typs[2])
|
||||
typs[119] = newSig(params(typs[3], typs[15], typs[15], typs[15], typs[1]), params(typs[118]))
|
||||
typs[120] = newSig(params(typs[1], typs[7], typs[22]), nil)
|
||||
typs[121] = newSig(params(typs[7], typs[22]), nil)
|
||||
typs[122] = newSig(params(typs[3], typs[3], typs[5]), nil)
|
||||
typs[123] = newSig(params(typs[7], typs[5]), nil)
|
||||
typs[124] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
|
||||
typs[125] = newSig(params(typs[3], typs[3]), params(typs[6]))
|
||||
typs[126] = newSig(params(typs[7], typs[7]), params(typs[6]))
|
||||
typs[127] = newSig(params(typs[3], typs[5], typs[5]), params(typs[5]))
|
||||
typs[128] = newSig(params(typs[7], typs[5]), params(typs[5]))
|
||||
typs[129] = newSig(params(typs[3], typs[5]), params(typs[5]))
|
||||
typs[130] = newSig(params(typs[22], typs[22]), params(typs[22]))
|
||||
typs[131] = newSig(params(typs[24], typs[24]), params(typs[24]))
|
||||
typs[132] = newSig(params(typs[20]), params(typs[22]))
|
||||
typs[133] = newSig(params(typs[20]), params(typs[24]))
|
||||
typs[134] = newSig(params(typs[20]), params(typs[60]))
|
||||
typs[135] = newSig(params(typs[22]), params(typs[20]))
|
||||
typs[136] = types.Types[types.TFLOAT32]
|
||||
typs[137] = newSig(params(typs[22]), params(typs[136]))
|
||||
typs[138] = newSig(params(typs[24]), params(typs[20]))
|
||||
typs[139] = newSig(params(typs[24]), params(typs[136]))
|
||||
typs[140] = newSig(params(typs[60]), params(typs[20]))
|
||||
typs[141] = newSig(params(typs[26], typs[26]), params(typs[26]))
|
||||
typs[142] = newSig(nil, params(typs[5]))
|
||||
typs[143] = newSig(params(typs[5], typs[5]), nil)
|
||||
typs[144] = newSig(params(typs[5], typs[5], typs[5]), nil)
|
||||
typs[145] = newSig(params(typs[7], typs[1], typs[5]), nil)
|
||||
typs[146] = types.NewSlice(typs[7])
|
||||
typs[147] = newSig(params(typs[7], typs[146]), nil)
|
||||
typs[148] = newSig(params(typs[64], typs[64], typs[17]), nil)
|
||||
typs[149] = newSig(params(typs[58], typs[58], typs[17]), nil)
|
||||
typs[150] = newSig(params(typs[60], typs[60], typs[17]), nil)
|
||||
typs[151] = newSig(params(typs[24], typs[24], typs[17]), nil)
|
||||
typs[152] = newSig(params(typs[28], typs[28], typs[17]), nil)
|
||||
typs[153] = types.NewArray(typs[0], 16)
|
||||
typs[154] = newSig(params(typs[7], typs[60], typs[153], typs[28], typs[15], typs[64], typs[64]), params(typs[60]))
|
||||
typs[73] = newSig(params(typs[15]), nil)
|
||||
typs[74] = newSig(nil, params(typs[10]))
|
||||
typs[75] = newSig(nil, params(typs[60]))
|
||||
typs[76] = types.NewMap(typs[2], typs[2])
|
||||
typs[77] = newSig(params(typs[1], typs[22], typs[3]), params(typs[76]))
|
||||
typs[78] = newSig(params(typs[1], typs[15], typs[3]), params(typs[76]))
|
||||
typs[79] = newSig(nil, params(typs[76]))
|
||||
typs[80] = newSig(params(typs[1], typs[76], typs[3]), params(typs[3]))
|
||||
typs[81] = newSig(params(typs[1], typs[76], typs[60]), params(typs[3]))
|
||||
typs[82] = newSig(params(typs[1], typs[76], typs[24]), params(typs[3]))
|
||||
typs[83] = newSig(params(typs[1], typs[76], typs[28]), params(typs[3]))
|
||||
typs[84] = newSig(params(typs[1], typs[76], typs[3], typs[1]), params(typs[3]))
|
||||
typs[85] = newSig(params(typs[1], typs[76], typs[3]), params(typs[3], typs[6]))
|
||||
typs[86] = newSig(params(typs[1], typs[76], typs[60]), params(typs[3], typs[6]))
|
||||
typs[87] = newSig(params(typs[1], typs[76], typs[24]), params(typs[3], typs[6]))
|
||||
typs[88] = newSig(params(typs[1], typs[76], typs[28]), params(typs[3], typs[6]))
|
||||
typs[89] = newSig(params(typs[1], typs[76], typs[3], typs[1]), params(typs[3], typs[6]))
|
||||
typs[90] = newSig(params(typs[1], typs[76], typs[7]), params(typs[3]))
|
||||
typs[91] = newSig(params(typs[1], typs[76], typs[3]), nil)
|
||||
typs[92] = newSig(params(typs[1], typs[76], typs[60]), nil)
|
||||
typs[93] = newSig(params(typs[1], typs[76], typs[24]), nil)
|
||||
typs[94] = newSig(params(typs[1], typs[76], typs[28]), nil)
|
||||
typs[95] = newSig(params(typs[3]), nil)
|
||||
typs[96] = newSig(params(typs[1], typs[76]), nil)
|
||||
typs[97] = types.NewChan(typs[2], types.Cboth)
|
||||
typs[98] = newSig(params(typs[1], typs[22]), params(typs[97]))
|
||||
typs[99] = newSig(params(typs[1], typs[15]), params(typs[97]))
|
||||
typs[100] = types.NewChan(typs[2], types.Crecv)
|
||||
typs[101] = newSig(params(typs[100], typs[3]), nil)
|
||||
typs[102] = newSig(params(typs[100], typs[3]), params(typs[6]))
|
||||
typs[103] = types.NewChan(typs[2], types.Csend)
|
||||
typs[104] = newSig(params(typs[103], typs[3]), nil)
|
||||
typs[105] = newSig(params(typs[103]), nil)
|
||||
typs[106] = newSig(params(typs[2]), params(typs[15]))
|
||||
typs[107] = types.NewArray(typs[0], 3)
|
||||
typs[108] = types.NewStruct([]*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[107]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])})
|
||||
typs[109] = newSig(params(typs[1], typs[3], typs[3]), nil)
|
||||
typs[110] = newSig(params(typs[1], typs[3]), nil)
|
||||
typs[111] = newSig(params(typs[1], typs[3], typs[15], typs[3], typs[15]), params(typs[15]))
|
||||
typs[112] = newSig(params(typs[103], typs[3]), params(typs[6]))
|
||||
typs[113] = newSig(params(typs[3], typs[100]), params(typs[6], typs[6]))
|
||||
typs[114] = newSig(params(typs[71]), nil)
|
||||
typs[115] = newSig(params(typs[1], typs[1], typs[71], typs[15], typs[15], typs[6]), params(typs[15], typs[6]))
|
||||
typs[116] = newSig(params(typs[1], typs[15], typs[15]), params(typs[7]))
|
||||
typs[117] = newSig(params(typs[1], typs[22], typs[22]), params(typs[7]))
|
||||
typs[118] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7]))
|
||||
typs[119] = types.NewSlice(typs[2])
|
||||
typs[120] = newSig(params(typs[3], typs[15], typs[15], typs[15], typs[1]), params(typs[119]))
|
||||
typs[121] = newSig(params(typs[1], typs[7], typs[22]), nil)
|
||||
typs[122] = newSig(params(typs[7], typs[22]), nil)
|
||||
typs[123] = newSig(params(typs[3], typs[3], typs[5]), nil)
|
||||
typs[124] = newSig(params(typs[7], typs[5]), nil)
|
||||
typs[125] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
|
||||
typs[126] = newSig(params(typs[3], typs[3]), params(typs[6]))
|
||||
typs[127] = newSig(params(typs[7], typs[7]), params(typs[6]))
|
||||
typs[128] = newSig(params(typs[3], typs[5], typs[5]), params(typs[5]))
|
||||
typs[129] = newSig(params(typs[7], typs[5]), params(typs[5]))
|
||||
typs[130] = newSig(params(typs[3], typs[5]), params(typs[5]))
|
||||
typs[131] = newSig(params(typs[22], typs[22]), params(typs[22]))
|
||||
typs[132] = newSig(params(typs[24], typs[24]), params(typs[24]))
|
||||
typs[133] = newSig(params(typs[20]), params(typs[22]))
|
||||
typs[134] = newSig(params(typs[20]), params(typs[24]))
|
||||
typs[135] = newSig(params(typs[20]), params(typs[60]))
|
||||
typs[136] = newSig(params(typs[22]), params(typs[20]))
|
||||
typs[137] = types.Types[types.TFLOAT32]
|
||||
typs[138] = newSig(params(typs[22]), params(typs[137]))
|
||||
typs[139] = newSig(params(typs[24]), params(typs[20]))
|
||||
typs[140] = newSig(params(typs[24]), params(typs[137]))
|
||||
typs[141] = newSig(params(typs[60]), params(typs[20]))
|
||||
typs[142] = newSig(params(typs[26], typs[26]), params(typs[26]))
|
||||
typs[143] = newSig(nil, params(typs[5]))
|
||||
typs[144] = newSig(params(typs[5], typs[5]), nil)
|
||||
typs[145] = newSig(params(typs[5], typs[5], typs[5]), nil)
|
||||
typs[146] = newSig(params(typs[7], typs[1], typs[5]), nil)
|
||||
typs[147] = types.NewSlice(typs[7])
|
||||
typs[148] = newSig(params(typs[7], typs[147]), nil)
|
||||
typs[149] = newSig(params(typs[64], typs[64], typs[17]), nil)
|
||||
typs[150] = newSig(params(typs[58], typs[58], typs[17]), nil)
|
||||
typs[151] = newSig(params(typs[60], typs[60], typs[17]), nil)
|
||||
typs[152] = newSig(params(typs[24], typs[24], typs[17]), nil)
|
||||
typs[153] = newSig(params(typs[28], typs[28], typs[17]), nil)
|
||||
typs[154] = types.NewArray(typs[0], 16)
|
||||
typs[155] = newSig(params(typs[7], typs[60], typs[154], typs[28], typs[15], typs[64], typs[64]), params(typs[60]))
|
||||
return typs[:]
|
||||
}
|
||||
|
||||
|
|
|
|||
50
src/cmd/compile/internal/types2/compiler_internal.go
Normal file
50
src/cmd/compile/internal/types2/compiler_internal.go
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
package types2
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/syntax"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// This file should not be copied to go/types. See go.dev/issue/67477
|
||||
|
||||
// RenameResult takes an array of (result) fields and an index, and if the indexed field
|
||||
// does not have a name and if the result in the signature also does not have a name,
|
||||
// then the signature and field are renamed to
|
||||
//
|
||||
// fmt.Sprintf("#rv%d", i+1)`
|
||||
//
|
||||
// the newly named object is inserted into the signature's scope,
|
||||
// and the object and new field name are returned.
|
||||
//
|
||||
// The intended use for RenameResult is to allow rangefunc to assign results within a closure.
|
||||
// This is a hack, as narrowly targeted as possible to discourage abuse.
|
||||
func (s *Signature) RenameResult(results []*syntax.Field, i int) (*Var, *syntax.Name) {
|
||||
a := results[i]
|
||||
obj := s.Results().At(i)
|
||||
|
||||
if !(obj.name == "" || obj.name == "_" && a.Name == nil || a.Name.Value == "_") {
|
||||
panic("Cannot change an existing name")
|
||||
}
|
||||
|
||||
pos := a.Pos()
|
||||
typ := a.Type.GetTypeInfo().Type
|
||||
|
||||
name := fmt.Sprintf("#rv%d", i+1)
|
||||
obj.name = name
|
||||
s.scope.Insert(obj)
|
||||
obj.setScopePos(pos)
|
||||
|
||||
tv := syntax.TypeAndValue{Type: typ}
|
||||
tv.SetIsValue()
|
||||
|
||||
n := syntax.NewName(pos, obj.Name())
|
||||
n.SetTypeInfo(tv)
|
||||
|
||||
a.Name = n
|
||||
|
||||
return obj, n
|
||||
}
|
||||
|
|
@ -81,7 +81,7 @@ var builtins = [...]struct {
|
|||
{"runtime.interfaceSwitch", 1},
|
||||
{"runtime.ifaceeq", 1},
|
||||
{"runtime.efaceeq", 1},
|
||||
{"runtime.panicrangeexit", 1},
|
||||
{"runtime.panicrangestate", 1},
|
||||
{"runtime.deferrangefunc", 1},
|
||||
{"runtime.rand32", 1},
|
||||
{"runtime.makemap64", 1},
|
||||
|
|
@ -116,6 +116,8 @@ var builtins = [...]struct {
|
|||
{"runtime.chanrecv2", 1},
|
||||
{"runtime.chansend1", 1},
|
||||
{"runtime.closechan", 1},
|
||||
{"runtime.chanlen", 1},
|
||||
{"runtime.chancap", 1},
|
||||
{"runtime.writeBarrier", 0},
|
||||
{"runtime.typedmemmove", 1},
|
||||
{"runtime.typedmemclr", 1},
|
||||
|
|
|
|||
|
|
@ -297,11 +297,31 @@ func deferproc(fn func()) {
|
|||
// been set and must not be clobbered.
|
||||
}
|
||||
|
||||
var rangeExitError = error(errorString("range function continued iteration after exit"))
|
||||
var rangeDoneError = error(errorString("range function continued iteration after loop body exit"))
|
||||
var rangePanicError = error(errorString("range function continued iteration after loop body panic"))
|
||||
var rangeExhaustedError = error(errorString("range function continued iteration after whole loop exit"))
|
||||
var rangeMissingPanicError = error(errorString("range function recovered a loop body panic and did not resume panicking"))
|
||||
|
||||
//go:noinline
|
||||
func panicrangeexit() {
|
||||
panic(rangeExitError)
|
||||
func panicrangestate(state int) {
|
||||
const (
|
||||
// These duplicate magic numbers in cmd/compile/internal/rangefunc
|
||||
DONE = 0 // body of loop has exited in a non-panic way
|
||||
PANIC = 2 // body of loop is either currently running, or has panicked
|
||||
EXHAUSTED = 3 // iterator function return, i.e., sequence is "exhausted"
|
||||
MISSING_PANIC = 4 // body of loop panicked but iterator function defer-recovered it away
|
||||
)
|
||||
switch state {
|
||||
case DONE:
|
||||
panic(rangeDoneError)
|
||||
case PANIC:
|
||||
panic(rangePanicError)
|
||||
case EXHAUSTED:
|
||||
panic(rangeExhaustedError)
|
||||
case MISSING_PANIC:
|
||||
panic(rangeMissingPanicError)
|
||||
}
|
||||
throw("unexpected state passed to panicrangestate")
|
||||
}
|
||||
|
||||
// deferrangefunc is called by functions that are about to
|
||||
|
|
|
|||
77
src/runtime/race/testdata/rangefunc_test.go
vendored
Normal file
77
src/runtime/race/testdata/rangefunc_test.go
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2024 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 goexperiment.rangefunc
|
||||
|
||||
package race_test
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type Seq2[T1, T2 any] func(yield func(T1, T2) bool)
|
||||
|
||||
// ofSliceIndex returns a Seq over the elements of s. It is equivalent
|
||||
// to range s, except that it splits s into two halves and iterates
|
||||
// in two separate goroutines. This is racy if yield is racy, and yield
|
||||
// will be racy if it contains an early exit.
|
||||
func ofSliceIndex[T any, S ~[]T](s S) Seq2[int, T] {
|
||||
return func(yield func(int, T) bool) {
|
||||
c := make(chan bool, 2)
|
||||
var done atomic.Bool
|
||||
go func() {
|
||||
for i := 0; i < len(s)/2; i++ {
|
||||
if !done.Load() && !yield(i, s[i]) {
|
||||
done.Store(true)
|
||||
c <- false
|
||||
}
|
||||
}
|
||||
c <- true
|
||||
}()
|
||||
go func() {
|
||||
for i := len(s) / 2; i < len(s); i++ {
|
||||
if !done.Load() && !yield(i, s[i]) {
|
||||
done.Store(true)
|
||||
c <- false
|
||||
}
|
||||
}
|
||||
c <- true
|
||||
return
|
||||
}()
|
||||
if !<-c {
|
||||
return
|
||||
}
|
||||
<-c
|
||||
}
|
||||
}
|
||||
|
||||
// foo is racy, or not, depending on the value of v
|
||||
// (0-4 == racy, otherwise, not racy).
|
||||
func foo(v int) int64 {
|
||||
var asum atomic.Int64
|
||||
for i, x := range ofSliceIndex([]int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
|
||||
if i%5 == v {
|
||||
break
|
||||
}
|
||||
asum.Add(x) // don't race on asum
|
||||
runtime.Gosched()
|
||||
}
|
||||
return 100 + asum.Load()
|
||||
}
|
||||
|
||||
// TestRaceRangeFuncIterator races because x%5 can be equal to 4,
|
||||
// therefore foo can early exit.
|
||||
func TestRaceRangeFuncIterator(t *testing.T) {
|
||||
x := foo(4)
|
||||
t.Logf("foo(4)=%d", x)
|
||||
}
|
||||
|
||||
// TestNoRaceRangeFuncIterator does not race because x%5 is never 5,
|
||||
// therefore foo's loop will not exit early, and this it will not race.
|
||||
func TestNoRaceRangeFuncIterator(t *testing.T) {
|
||||
x := foo(5)
|
||||
t.Logf("foo(5)=%d", x)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue