There's several copies of this function. We only need one.
While here, normalize so that we always declare parameters, and always
use the names ~pNN for params and ~rNN for results.
Change-Id: I49e90d3fd1820f3c07936227ed5cfefd75d49a1c
Reviewed-on: https://go-review.googlesource.com/c/go/+/528415
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Than McIntosh <thanm@google.com>
*condLevelTracker
}
-// dclParams returns a slice containing the non-blank, named params
-// for the specific function (plus rcvr as well if applicable) in
-// declaration order.
-func dclParams(fn *ir.Func) []*ir.Name {
- params := []*ir.Name{}
- for _, n := range fn.Dcl {
- if n.Op() != ir.ONAME {
- continue
- }
- if n.Class != ir.PPARAM {
- continue
- }
- params = append(params, n)
- }
- return params
-}
-
// getParams returns an *ir.Name slice containing all params for the
-// function (plus rcvr as well if applicable). Note that this slice
-// includes entries for blanks; entries in the returned slice corresponding
-// to blanks or unnamed params will be nil.
+// function (plus rcvr as well if applicable).
func getParams(fn *ir.Func) []*ir.Name {
- dclparms := dclParams(fn)
- dclidx := 0
- recvrParms := fn.Type().RecvParams()
- params := make([]*ir.Name, len(recvrParms))
- for i := range recvrParms {
- var v *ir.Name
- if recvrParms[i].Sym != nil &&
- !recvrParms[i].Sym.IsBlank() {
- v = dclparms[dclidx]
- dclidx++
- }
- params[i] = v
- }
- return params
+ sig := fn.Type()
+ numParams := sig.NumRecvs() + sig.NumParams()
+ return fn.Dcl[:numParams]
}
func makeParamsAnalyzer(fn *ir.Func) *paramsAnalyzer {
// include closurevars until transforming closures during walk.
// Names must be listed PPARAMs, PPARAMOUTs, then PAUTOs,
// with PPARAMs and PPARAMOUTs in order corresponding to the function signature.
- // However, as anonymous or blank PPARAMs are not actually declared,
- // they are omitted from Dcl.
- // Anonymous and blank PPARAMOUTs are declared as ~rNN and ~bNN Names, respectively.
+ // Anonymous and blank params are declared as ~pNN (for PPARAMs) and ~rNN (for PPARAMOUTs).
Dcl []*Name
// ClosureVars lists the free variables that are used within a
return (fn.Name == "FuncPCABI0" || fn.Name == "FuncPCABIInternal") &&
fn.Pkg.Path == "internal/abi"
}
+
+// DeclareParams creates Names for all of the parameters in fn's
+// signature and adds them to fn.Dcl.
+//
+// If setNname is true, then it also sets types.Field.Nname for each
+// parameter.
+func (fn *Func) DeclareParams(setNname bool) {
+ if fn.Dcl != nil {
+ base.FatalfAt(fn.Pos(), "%v already has Dcl", fn)
+ }
+
+ declareParams := func(params []*types.Field, ctxt Class, prefix string, offset int) {
+ for i, param := range params {
+ sym := param.Sym
+ if sym == nil || sym.IsBlank() {
+ sym = fn.Sym().Pkg.LookupNum(prefix, i)
+ }
+
+ name := NewNameAt(param.Pos, sym, param.Type)
+ name.Class = ctxt
+ name.Curfn = fn
+ fn.Dcl[offset+i] = name
+
+ if setNname {
+ param.Nname = name
+ }
+ }
+ }
+
+ sig := fn.Type()
+ params := sig.RecvParams()
+ results := sig.Results()
+
+ fn.Dcl = make([]*Name, len(params)+len(results))
+ declareParams(params, PPARAM, "~p", 0)
+ declareParams(results, PPARAMOUT, "~r", len(params))
+}
}
// NewLocal returns a new function-local variable with the given name and type.
-func (fn *Func) NewLocal(pos src.XPos, sym *types.Sym, class Class, typ *types.Type) *Name {
- switch class {
- case PPARAM, PPARAMOUT, PAUTO:
- // ok
- default:
- base.FatalfAt(pos, "NewLocal: unexpected class for %v: %v", sym, class)
+func (fn *Func) NewLocal(pos src.XPos, sym *types.Sym, typ *types.Type) *Name {
+ if fn.Dcl == nil {
+ base.FatalfAt(pos, "must call DeclParams on %v first", fn)
}
n := NewNameAt(pos, sym, typ)
- n.Class = class
+ n.Class = PAUTO
n.Curfn = fn
fn.Dcl = append(fn.Dcl, n)
return n
return false
}
-// Nodes is a pointer to a slice of *Node.
-// For fields that are not used in most nodes, this is used instead of
-// a slice to save space.
+// Nodes is a slice of Node.
type Nodes []Node
+// ToNodes returns s as a slice of Nodes.
+func ToNodes[T Node](s []T) Nodes {
+ res := make(Nodes, len(s))
+ for i, n := range s {
+ res[i] = n
+ }
+ return res
+}
+
// Append appends entries to Nodes.
func (n *Nodes) Append(a ...Node) {
if len(a) == 0 {
`"relatedInformation":[`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y := z (assign-pair)"},`+
- `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~R0 = y:"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~r0 = y:"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from \u0026y.b (address-of)"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+
- `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~R0 = \u0026y.b (assign-pair)"},`+
- `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r0 = ~R0:"},`+
- `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return ~R0 (return)"}]}`)
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~r0 = \u0026y.b (assign-pair)"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r0 = ~r0:"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return ~r0 (return)"}]}`)
})
}
locals []*ir.Name
closureVars []*ir.Name
+ // funarghack is used during inlining to suppress setting
+ // Field.Nname to the inlined copies of the parameters. This is
+ // necessary because we reuse the same types.Type as the original
+ // function, and most of the compiler still relies on field.Nname to
+ // find parameters/results.
funarghack bool
// methodSym is the name of method's name, if reading a method.
// Label to return to.
retlabel *types.Sym
-
- // inlvars is the list of variables that the inlinee's arguments are
- // assigned to, one for each receiver and normal parameter, in order.
- inlvars ir.Nodes
-
- // retvars is the list of variables that the inlinee's results are
- // assigned to, one for each result parameter, in order.
- retvars ir.Nodes
}
// A readerDict represents an instantiated "compile-time dictionary,"
}
ir.WithFunc(fn, func() {
- r.funcargs(fn)
+ r.declareParams()
if r.syntheticBody(fn.Pos()) {
return
shapedFn = shapedMethodExpr(pos, shapedObj, r.methodSym)
}
- recvs, params := r.syntheticArgs(pos)
+ params := r.syntheticArgs()
// Construct the arguments list: receiver (if any), then runtime
// dictionary, and finally normal parameters.
// putting the dictionary parameter after that is the least invasive
// solution at the moment.
var args ir.Nodes
- args.Append(recvs...)
+ if r.methodSym != nil {
+ args.Append(params[0])
+ params = params[1:]
+ }
args.Append(typecheck.Expr(ir.NewAddrExpr(pos, r.p.dictNameOf(r.dict))))
args.Append(params...)
// syntheticArgs returns the recvs and params arguments passed to the
// current function.
-func (r *reader) syntheticArgs(pos src.XPos) (recvs, params ir.Nodes) {
+func (r *reader) syntheticArgs() ir.Nodes {
sig := r.curfn.Nname.Type()
-
- inlVarIdx := 0
- addParams := func(out *ir.Nodes, params []*types.Field) {
- for _, param := range params {
- var arg ir.Node
- if param.Nname != nil {
- name := param.Nname.(*ir.Name)
- if !ir.IsBlank(name) {
- if r.inlCall != nil {
- // During inlining, we want the respective inlvar where we
- // assigned the callee's arguments.
- arg = r.inlvars[inlVarIdx]
- } else {
- // Otherwise, we can use the parameter itself directly.
- base.AssertfAt(name.Curfn == r.curfn, name.Pos(), "%v has curfn %v, but want %v", name, name.Curfn, r.curfn)
- arg = name
- }
- }
- }
-
- // For anonymous and blank parameters, we don't have an *ir.Name
- // to use as the argument. However, since we know the shaped
- // function won't use the value either, we can just pass the
- // zero value.
- if arg == nil {
- arg = ir.NewZero(pos, param.Type)
- }
-
- out.Append(arg)
- inlVarIdx++
- }
- }
-
- addParams(&recvs, sig.Recvs())
- addParams(¶ms, sig.Params())
- return
+ return ir.ToNodes(r.curfn.Dcl[:sig.NumRecvs()+sig.NumParams()])
}
// syntheticTailCall emits a tail call to fn, passing the given
return types.NewArray(types.Types[types.TUINTPTR], dict.numWords())
}
-func (r *reader) funcargs(fn *ir.Func) {
- sig := fn.Nname.Type()
-
- if recv := sig.Recv(); recv != nil {
- r.funcarg(recv, recv.Sym, ir.PPARAM)
- }
- for _, param := range sig.Params() {
- r.funcarg(param, param.Sym, ir.PPARAM)
- }
-
- for i, param := range sig.Results() {
- sym := param.Sym
+func (r *reader) declareParams() {
+ r.curfn.DeclareParams(!r.funarghack)
- if sym == nil || sym.IsBlank() {
- prefix := "~r"
- if r.inlCall != nil {
- prefix = "~R"
- } else if sym != nil {
- prefix = "~b"
- }
- sym = typecheck.LookupNum(prefix, i)
+ for _, name := range r.curfn.Dcl {
+ if name.Sym().Name == dictParamName {
+ r.dictParam = name
+ continue
}
- r.funcarg(param, sym, ir.PPARAMOUT)
+ r.addLocal(name)
}
}
-func (r *reader) funcarg(param *types.Field, sym *types.Sym, ctxt ir.Class) {
- if sym == nil {
- assert(ctxt == ir.PPARAM)
- if r.inlCall != nil {
- r.inlvars.Append(ir.BlankNode)
- }
- return
- }
-
- name := r.addLocal(r.inlPos(param.Pos), sym, ctxt, param.Type)
-
- if r.inlCall == nil {
- if !r.funarghack {
- param.Nname = name
- }
- } else {
- if ctxt == ir.PPARAMOUT {
- r.retvars.Append(name)
- } else {
- r.inlvars.Append(name)
- }
- }
-}
-
-func (r *reader) addLocal(pos src.XPos, sym *types.Sym, ctxt ir.Class, typ *types.Type) *ir.Name {
- assert(ctxt == ir.PAUTO || ctxt == ir.PPARAM || ctxt == ir.PPARAMOUT)
-
- name := ir.NewNameAt(pos, sym, typ)
-
- if name.Sym().Name == dictParamName {
- r.dictParam = name
- } else {
- if r.synthetic == nil {
- r.Sync(pkgbits.SyncAddLocal)
- if r.p.SyncMarkers() {
- want := r.Int()
- if have := len(r.locals); have != want {
- base.FatalfAt(name.Pos(), "locals table has desynced")
- }
+func (r *reader) addLocal(name *ir.Name) {
+ if r.synthetic == nil {
+ r.Sync(pkgbits.SyncAddLocal)
+ if r.p.SyncMarkers() {
+ want := r.Int()
+ if have := len(r.locals); have != want {
+ base.FatalfAt(name.Pos(), "locals table has desynced")
}
- r.varDictIndex(name)
}
-
- r.locals = append(r.locals, name)
- }
-
- name.SetUsed(true)
-
- // TODO(mdempsky): Move earlier.
- if ir.IsBlank(name) {
- return name
+ r.varDictIndex(name)
}
- if r.inlCall != nil {
- if ctxt == ir.PAUTO {
- name.SetInlLocal(true)
- } else {
- name.SetInlFormal(true)
- ctxt = ir.PAUTO
- }
- }
-
- name.Class = ctxt
- name.Curfn = r.curfn
-
- r.curfn.Dcl = append(r.curfn.Dcl, name)
-
- if ctxt == ir.PAUTO {
- name.SetFrameOffset(0)
- }
-
- return name
+ r.locals = append(r.locals, name)
}
func (r *reader) useLocal() *ir.Name {
_, sym := r.localIdent()
typ := r.typ()
- name := r.addLocal(pos, sym, ir.PAUTO, typ)
+ name := r.curfn.NewLocal(pos, sym, typ)
+ r.addLocal(name)
return name, true
case assignExpr:
clause.RTypes = rtypes
if ident != nil {
- pos := r.pos()
- typ := r.typ()
-
- name := r.addLocal(pos, ident.Sym(), ir.PAUTO, typ)
+ name := r.curfn.NewLocal(r.pos(), ident.Sym(), r.typ())
+ r.addLocal(name)
clause.Var = name
name.Defn = tag
}
typ := types.NewSignature(nil, params, results)
addBody := func(pos src.XPos, r *reader, captured []ir.Node) {
- recvs, params := r.syntheticArgs(pos)
- assert(len(recvs) == 0)
-
fun := captured[0]
var args ir.Nodes
args.Append(captured[1:]...)
- args.Append(params...)
+ args.Append(r.syntheticArgs()...)
r.syntheticTailCall(pos, fun, args)
}
typ := types.NewSignature(nil, params, results)
addBody := func(pos src.XPos, r *reader, captured []ir.Node) {
- recvs, args := r.syntheticArgs(pos)
- assert(len(recvs) == 0)
-
fn := captured[0]
+ args := r.syntheticArgs()
// Rewrite first argument based on implicits/deref/addr.
{
clone := func(params []*types.Field) []*types.Field {
res := make([]*types.Field, len(params))
for i, param := range params {
- sym := param.Sym
- if sym == nil || sym.Name == "_" {
- sym = typecheck.LookupNum(".anon", i)
- }
// 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] = types.NewField(base.AutogeneratedPos, param.Sym, param.Type)
res[i].SetIsDDD(param.IsDDD())
}
return res
r.inlFunc = fn
r.inlTreeIndex = inlIndex
r.inlPosBases = make(map[*src.PosBase]*src.PosBase)
+ r.funarghack = true
r.closureVars = make([]*ir.Name, len(r.inlFunc.ClosureVars))
for i, cv := range r.inlFunc.ClosureVars {
r.dictParam = r.closureVars[len(r.closureVars)-1] // dictParam is last; see reader.funcLit
}
- r.funcargs(fn)
+ r.declareParams()
+
+ var inlvars, retvars []*ir.Name
+ {
+ sig := r.curfn.Type()
+ endParams := sig.NumRecvs() + sig.NumParams()
+ endResults := endParams + sig.NumResults()
+
+ inlvars = r.curfn.Dcl[:endParams]
+ retvars = r.curfn.Dcl[endParams:endResults]
+ }
r.delayResults = fn.Inl.CanDelayResults
args.Append(call.Args...)
// Create assignment to declare and initialize inlvars.
- as2 := ir.NewAssignListStmt(call.Pos(), ir.OAS2, r.inlvars, args)
+ as2 := ir.NewAssignListStmt(call.Pos(), ir.OAS2, ir.ToNodes(inlvars), args)
as2.Def = true
var as2init ir.Nodes
- for _, name := range r.inlvars {
+ for _, name := range inlvars {
if ir.IsBlank(name) {
continue
}
// TODO(mdempsky): Use inlined position of name.Pos() instead?
- name := name.(*ir.Name)
as2init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name))
name.Defn = as2
}
if !r.delayResults {
// If not delaying retvars, declare and zero initialize the
// result variables now.
- for _, name := range r.retvars {
+ for _, name := range retvars {
// TODO(mdempsky): Use inlined position of name.Pos() instead?
- name := name.(*ir.Name)
init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name))
ras := ir.NewAssignStmt(call.Pos(), name, nil)
init.Append(typecheck.Stmt(ras))
var edit func(ir.Node) ir.Node
edit = func(n ir.Node) ir.Node {
if ret, ok := n.(*ir.ReturnStmt); ok {
- n = typecheck.Stmt(r.inlReturn(ret))
+ n = typecheck.Stmt(r.inlReturn(ret, retvars))
}
ir.EditChildren(n, edit)
return n
// Reparent any declarations into the caller function.
for _, name := range r.curfn.Dcl {
name.Curfn = callerfn
- callerfn.Dcl = append(callerfn.Dcl, name)
- if name.AutoTemp() {
- name.SetEsc(ir.EscUnknown)
+ if name.Class != ir.PAUTO {
+ name.SetPos(r.inlPos(name.Pos()))
+ name.SetInlFormal(true)
+ name.Class = ir.PAUTO
+ } else {
name.SetInlLocal(true)
}
}
+ callerfn.Dcl = append(callerfn.Dcl, r.curfn.Dcl...)
body.Append(ir.NewLabelStmt(call.Pos(), r.retlabel))
- res := ir.NewInlinedCallExpr(call.Pos(), body, append([]ir.Node(nil), r.retvars...))
+ res := ir.NewInlinedCallExpr(call.Pos(), body, ir.ToNodes(retvars))
res.SetInit(init)
res.SetType(call.Type())
res.SetTypecheck(1)
// inlReturn returns a statement that can substitute for the given
// return statement when inlining.
-func (r *reader) inlReturn(ret *ir.ReturnStmt) *ir.BlockStmt {
+func (r *reader) inlReturn(ret *ir.ReturnStmt, retvars []*ir.Name) *ir.BlockStmt {
pos := r.inlCall.Pos()
block := ir.TakeInit(ret)
if results := ret.Results; len(results) != 0 {
- assert(len(r.retvars) == len(results))
+ assert(len(retvars) == len(results))
- as2 := ir.NewAssignListStmt(pos, ir.OAS2, append([]ir.Node(nil), r.retvars...), ret.Results)
+ as2 := ir.NewAssignListStmt(pos, ir.OAS2, ir.ToNodes(retvars), ret.Results)
if r.delayResults {
- for _, name := range r.retvars {
+ for _, name := range retvars {
// TODO(mdempsky): Use inlined position of name.Pos() instead?
- name := name.(*ir.Name)
block.Append(ir.NewDecl(pos, ir.ODCL, name))
name.Defn = as2
}
r.funcBody(tmpfn)
}
- used := usedLocals(tmpfn.Body)
-
+ // Move tmpfn's params to fn.Inl.Dcl, and reparent under fn.
for _, name := range tmpfn.Dcl {
- if name.Class != ir.PAUTO || used.Has(name) {
- name.Curfn = fn
- fn.Inl.Dcl = append(fn.Inl.Dcl, name)
- } else {
- // TODO(mdempsky): Simplify code after confident that this never
- // happens anymore.
- base.FatalfAt(name.Pos(), "unused auto: %v", name)
- }
+ name.Curfn = fn
}
+ fn.Inl.Dcl = tmpfn.Dcl
fn.Inl.HaveDcl = true
// Double check that we didn't change fn.Dcl by accident.
sig := newWrapperType(wrapper, method)
fn := ir.NewFunc(pos, pos, sym, sig)
+ fn.DeclareParams(true)
fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers?
- // TODO(mdempsky): De-duplicate with similar logic in funcargs.
- defParams := func(class ir.Class, params []*types.Field) {
- for _, param := range params {
- param.Nname = fn.NewLocal(param.Pos, param.Sym, class, param.Type)
- }
- }
-
- defParams(ir.PPARAM, sig.Recvs())
- defParams(ir.PPARAM, sig.Params())
- defParams(ir.PPARAMOUT, sig.Results())
-
return fn
}
clone := func(params []*types.Field) []*types.Field {
res := make([]*types.Field, len(params))
for i, param := range params {
- sym := param.Sym
- if sym == nil || sym.Name == "_" {
- sym = typecheck.LookupNum(".anon", i)
- }
- res[i] = types.NewField(param.Pos, sym, param.Type)
+ res[i] = types.NewField(param.Pos, param.Sym, param.Type)
res[i].SetIsDDD(param.IsDDD())
}
return res
var recv *types.Field
if recvType != nil {
- recv = types.NewField(sig.Recv().Pos, typecheck.Lookup(".this"), recvType)
+ recv = types.NewField(sig.Recv().Pos, sig.Recv().Sym, recvType)
}
params := clone(sig.Params())
results := clone(sig.Results())
w.sig = sig
w.dict = dict
- w.funcargs(sig)
+ w.declareParams(sig)
if w.Bool(block != nil) {
w.stmts(block.List)
w.pos(block.Rbrace)
return w.Flush(), w.closureVars
}
-func (w *writer) funcargs(sig *types2.Signature) {
- do := func(params *types2.Tuple, result bool) {
+func (w *writer) declareParams(sig *types2.Signature) {
+ addLocals := func(params *types2.Tuple) {
for i := 0; i < params.Len(); i++ {
- w.funcarg(params.At(i), result)
+ w.addLocal(params.At(i))
}
}
if recv := sig.Recv(); recv != nil {
- w.funcarg(recv, false)
- }
- do(sig.Params(), false)
- do(sig.Results(), true)
-}
-
-func (w *writer) funcarg(param *types2.Var, result bool) {
- if param.Name() != "" || result {
- w.addLocal(param)
+ w.addLocal(recv)
}
+ addLocals(sig.Params())
+ addLocals(sig.Results())
}
// addLocal records the declaration of a new local variable.
sym.Def = fn.Nname
fn.Pragma |= ir.Noinline // TODO(mdempsky): We need to emit this during the unified frontend instead, to allow inlining.
- params, _ := typecheck.DeclFunc(fn)
- np := params[0]
- nh := params[1]
+ typecheck.DeclFunc(fn)
+ np := fn.Dcl[0]
+ nh := fn.Dcl[1]
switch t.Kind() {
case types.TARRAY:
sym.Def = fn.Nname
fn.Pragma |= ir.Noinline // TODO(mdempsky): We need to emit this during the unified frontend instead, to allow inlining.
- params, results := typecheck.DeclFunc(fn)
- np := params[0]
- nq := params[1]
- nr := results[0]
+ typecheck.DeclFunc(fn)
+ np := fn.Dcl[0]
+ nq := fn.Dcl[1]
+ nr := fn.Dcl[2]
// Label to jump to if an equality test fails.
neq := typecheck.AutoLabel(".neq")
func (c *Conf) Frontend() Frontend {
if c.fe == nil {
- f := ir.NewFunc(src.NoXPos, src.NoXPos, &types.Sym{
- Pkg: types.NewPkg("my/import/path", "path"),
- Name: "function",
- }, nil)
- f.LSym = &obj.LSym{Name: "my/import/path.function"}
+ pkg := types.NewPkg("my/import/path", "path")
+ fn := ir.NewFunc(src.NoXPos, src.NoXPos, pkg.Lookup("function"), types.NewSignature(nil, nil, nil))
+ fn.DeclareParams(true)
+ fn.LSym = &obj.LSym{Name: "my/import/path.function"}
c.fe = TestFrontend{
t: c.tb,
ctxt: c.config.ctxt,
- f: f,
+ f: fn,
}
}
return c.fe
// Reuse f's types.Sym to create a new ODCLFUNC/function.
// TODO(mdempsky): Means we can't set sym.Def in Declfunc, ugh.
fn := ir.NewFunc(pos, pos, f.Sym(), types.NewSignature(nil,
- typecheck.NewFuncParams(ft.Params(), true),
- typecheck.NewFuncParams(ft.Results(), false)))
+ typecheck.NewFuncParams(ft.Params()),
+ typecheck.NewFuncParams(ft.Results())))
fn.ABI = wrapperABI
typecheck.DeclFunc(fn)
// Declare variable to hold address.
sym := &types.Sym{Name: "&" + n.Sym().Name, Pkg: types.LocalPkg}
- addr := s.curfn.NewLocal(pos, sym, ir.PAUTO, types.NewPtr(n.Type()))
+ addr := s.curfn.NewLocal(pos, sym, types.NewPtr(n.Type()))
addr.SetUsed(true)
types.CalcSize(addr.Type())
}
sym := &types.Sym{Name: node.Sym().Name + suffix, Pkg: types.LocalPkg}
- n := e.curfn.NewLocal(parent.N.Pos(), sym, ir.PAUTO, t)
+ n := e.curfn.NewLocal(parent.N.Pos(), sym, t)
n.SetUsed(true)
n.SetEsc(ir.EscNever)
types.CalcSize(t)
var funcStack []*ir.Func // stack of previous values of ir.CurFunc
-// DeclFunc creates and returns ONAMEs for the parameters and results
-// of the given function. It also sets ir.CurFunc, and adds fn to
+// DeclFunc declares the parameters for fn and adds it to
// Target.Funcs.
//
-// After the caller is done constructing fn, it must call
-// FinishFuncBody.
-func DeclFunc(fn *ir.Func) (params, results []*ir.Name) {
- typ := fn.Type()
-
- // Currently, DeclFunc is only used to create normal functions, not
- // methods. If a use case for creating methods shows up, we can
- // extend it to support those too.
- if typ.Recv() != nil {
- base.FatalfAt(fn.Pos(), "unexpected receiver parameter")
- }
-
- params = declareParams(fn, ir.PPARAM, typ.Params())
- results = declareParams(fn, ir.PPARAMOUT, typ.Results())
-
- funcStack = append(funcStack, ir.CurFunc)
- ir.CurFunc = fn
-
+// Before returning, it sets CurFunc to fn. When the caller is done
+// constructing fn, it must call FinishFuncBody to restore CurFunc.
+func DeclFunc(fn *ir.Func) {
+ fn.DeclareParams(true)
fn.Nname.Defn = fn
Target.Funcs = append(Target.Funcs, fn)
- return
+ funcStack = append(funcStack, ir.CurFunc)
+ ir.CurFunc = fn
}
// FinishFuncBody restores ir.CurFunc to its state before the last
}
}
-func declareParams(fn *ir.Func, ctxt ir.Class, params []*types.Field) []*ir.Name {
- names := make([]*ir.Name, len(params))
- for i, param := range params {
- names[i] = declareParam(fn, ctxt, i, param)
- }
- return names
-}
-
-func declareParam(fn *ir.Func, ctxt ir.Class, i int, param *types.Field) *ir.Name {
- sym := param.Sym
- if ctxt == ir.PPARAMOUT {
- if sym == nil {
- // Name so that escape analysis can track it. ~r stands for 'result'.
- sym = LookupNum("~r", i)
- } else if sym.IsBlank() {
- // Give it a name so we can assign to it during return. ~b stands for 'blank'.
- // The name must be different from ~r above because if you have
- // func f() (_ int)
- // func g() int
- // f is allowed to use a plain 'return' with no arguments, while g is not.
- // So the two cases must be distinguished.
- sym = LookupNum("~b", i)
- }
- }
-
- if sym == nil {
- return nil
- }
-
- name := fn.NewLocal(param.Pos, sym, ctxt, param.Type)
- param.Nname = name
- return name
-}
-
// make a new Node off the books.
-func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
+func TempAt(pos src.XPos, curfn *ir.Func, typ *types.Type) *ir.Name {
if curfn == nil {
- base.Fatalf("no curfn for TempAt")
+ base.FatalfAt(pos, "no curfn for TempAt")
}
- if t == nil {
- base.Fatalf("TempAt called with nil type")
+ if typ == nil {
+ base.FatalfAt(pos, "TempAt called with nil type")
}
- if t.Kind() == types.TFUNC && t.Recv() != nil {
- base.Fatalf("misuse of method type: %v", t)
+ if typ.Kind() == types.TFUNC && typ.Recv() != nil {
+ base.FatalfAt(pos, "misuse of method type: %v", typ)
}
+ types.CalcSize(typ)
- s := &types.Sym{
+ sym := &types.Sym{
Name: autotmpname(len(curfn.Dcl)),
Pkg: types.LocalPkg,
}
- n := curfn.NewLocal(pos, s, ir.PAUTO, t)
- s.Def = n // TODO(mdempsky): Should be unnecessary.
- n.SetEsc(ir.EscNever)
- n.SetUsed(true)
- n.SetAutoTemp(true)
+ name := curfn.NewLocal(pos, sym, typ)
+ name.SetEsc(ir.EscNever)
+ name.SetUsed(true)
+ name.SetAutoTemp(true)
- types.CalcSize(t)
-
- return n
+ return name
}
var (
// Create a new wrapper function without parameters or results.
wrapperFn := ir.NewClosureFunc(n.Pos(), n.Pos(), n.Op(), types.NewSignature(nil, nil, nil), ir.CurFunc, Target)
+ wrapperFn.DeclareParams(true)
wrapperFn.SetWrapper(true)
// argps collects the list of operands within the call expression
}
// Given funarg struct list, return list of fn args.
-func NewFuncParams(origs []*types.Field, mustname bool) []*types.Field {
+func NewFuncParams(origs []*types.Field) []*types.Field {
res := make([]*types.Field, len(origs))
for i, orig := range origs {
- s := orig.Sym
- if mustname && (s == nil || s.Name == "_") {
- // invent a name so that we can refer to it in the trampoline
- s = LookupNum(".anon", i)
- } else if s != nil && s.Pkg != types.LocalPkg {
- // TODO(mdempsky): Preserve original position, name, and package.
- s = Lookup(s.Name)
- }
- p := types.NewField(orig.Pos, s, orig.Type)
+ p := types.NewField(orig.Pos, orig.Sym, orig.Type)
p.SetIsDDD(orig.IsDDD())
res[i] = p
}
// errorcheck -0 -m -live -std
+//go:build !windows && !js && !wasip1
// +build !windows,!js,!wasip1
// Copyright 2015 The Go Authors. All rights reserved.
"unsafe"
)
-func implicit(uintptr) // ERROR "assuming arg#1 is unsafe uintptr"
+func implicit(uintptr) // ERROR "assuming ~p0 is unsafe uintptr"
//go:uintptrkeepalive
//go:nosplit
func localImplicit() { // ERROR "can inline localImplicit"
var t int
p := unsafe.Pointer(&t)
- implicit(uintptr(p)) // ERROR "live at call to implicit: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
+ implicit(uintptr(p)) // ERROR "live at call to implicit: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
}
func localExplicit() { // ERROR "can inline localExplicit"
var t int
p := unsafe.Pointer(&t)
- explicit(uintptr(p)) // ERROR "live at call to explicit: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
+ explicit(uintptr(p)) // ERROR "live at call to explicit: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
}
func localSyscall() { // ERROR "can inline localSyscall"