inlTreeIndex int
inlPosBases map[*src.PosBase]*src.PosBase
+ // suppressInlPos tracks whether position base rewriting for
+ // inlining should be suppressed. See funcLit.
+ suppressInlPos int
+
delayResults bool
// Label to return to.
return b
}
-// TODO(mdempsky): Document this.
+// inlPosBase returns the inlining-adjusted src.PosBase corresponding
+// to oldBase, which must be a non-inlined position. When not
+// inlining, this is just oldBase.
func (r *reader) inlPosBase(oldBase *src.PosBase) *src.PosBase {
- if r.inlCall == nil {
+ if index := oldBase.InliningIndex(); index >= 0 {
+ base.Fatalf("oldBase %v already has inlining index %v", oldBase, index)
+ }
+
+ if r.inlCall == nil || r.suppressInlPos != 0 {
return oldBase
}
return newBase
}
-// TODO(mdempsky): Document this.
-func (r *reader) updatePos(xpos src.XPos) src.XPos {
+// inlPos returns the inlining-adjusted src.XPos corresponding to
+// xpos, which must be a non-inlined position. When not inlining, this
+// is just xpos.
+func (r *reader) inlPos(xpos src.XPos) src.XPos {
pos := base.Ctxt.PosTable.Pos(xpos)
pos.SetBase(r.inlPosBase(pos.Base()))
return base.Ctxt.PosTable.XPos(pos)
return
}
- name := ir.NewNameAt(r.updatePos(param.Pos), sym)
+ name := ir.NewNameAt(r.inlPos(param.Pos), sym)
setType(name, param.Type)
r.addLocal(name, ctxt)
if sym == nil || sym.Name == "_" {
sym = typecheck.LookupNum(".anon", i)
}
- res[i] = types.NewField(param.Pos, sym, param.Type)
+ // TODO(mdempsky): It would be nice to preserve the original
+ // parameter positions here instead, but at least
+ // typecheck.NewMethodType replaces them with base.Pos, making
+ // them useless. Worse, the positions copied from base.Pos may
+ // have inlining contexts, which we definitely don't want here
+ // (e.g., #54625).
+ res[i] = types.NewField(base.AutogeneratedPos, sym, param.Type)
res[i].SetIsDDD(param.IsDDD())
}
return res
// otherwise, they need to create their own wrapper.
func (r *reader) methodExpr() (wrapperFn, baseFn, dictPtr ir.Node) {
recv := r.typ()
- sig0 := r.signature(types.LocalPkg, nil)
+ sig0 := r.typ()
pos := r.pos()
_, sym := r.selector()
func (r *reader) funcLit() ir.Node {
r.Sync(pkgbits.SyncFuncLit)
+ // The underlying function declaration (including its parameters'
+ // positions, if any) need to remain the original, uninlined
+ // positions. This is because we track inlining-context on nodes so
+ // we can synthesize the extra implied stack frames dynamically when
+ // generating tracebacks, whereas those stack frames don't make
+ // sense *within* the function literal. (Any necessary inlining
+ // adjustments will have been applied to the call expression
+ // instead.)
+ //
+ // This is subtle, and getting it wrong leads to cycles in the
+ // inlining tree, which lead to infinite loops during stack
+ // unwinding (#46234, #54625).
+ //
+ // Note that we *do* want the inline-adjusted position for the
+ // OCLOSURE node, because that position represents where any heap
+ // allocation of the closure is credited (#49171).
+ r.suppressInlPos++
pos := r.pos()
xtype2 := r.signature(types.LocalPkg, nil)
+ r.suppressInlPos--
- opos := pos
-
- fn := ir.NewClosureFunc(opos, r.curfn != nil)
+ fn := ir.NewClosureFunc(pos, r.curfn != nil)
clo := fn.OClosure
+ clo.SetPos(r.inlPos(pos)) // see comment above
ir.NameClosure(clo, r.curfn)
setType(fn.Nname, xtype2)