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
|
|
@ -90,15 +90,19 @@ 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
|
||||
goDeferGen int32
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue