"cmd/compile/internal/base"
"cmd/compile/internal/types"
"cmd/internal/src"
- "fmt"
)
// Calling TypeNode converts a *types.Type to a Node shell.
-// A Field is a declared function parameter.
-// It is not a Node.
-type Field struct {
- Pos src.XPos
- Sym *types.Sym
- Type *types.Type
- IsDDD bool
-}
-
-func NewField(pos src.XPos, sym *types.Sym, typ *types.Type) *Field {
- return &Field{Pos: pos, Sym: sym, Type: typ}
-}
-
-func (f *Field) String() string {
- if f.Sym != nil {
- return fmt.Sprintf("%v %v", f.Sym, f.Type)
- }
- return fmt.Sprint(f.Type)
-}
-
// A typeNode is a Node wrapper for type t.
type typeNode struct {
miniNode
}
// Make a function that contains all the initialization statements.
- base.Pos = nf[0].Pos() // prolog/epilog gets line number of first init stmt
- initializers := typecheck.Lookup("init")
- fn := typecheck.DeclFunc(initializers, nil, nil, nil)
+ pos := nf[0].Pos() // prolog/epilog gets line number of first init stmt
+ base.Pos = pos
+
+ sym := typecheck.Lookup("init")
+ fn := ir.NewFunc(pos, pos, sym, types.NewSignature(nil, nil, nil))
+ typecheck.DeclFunc(fn)
+
for _, dcl := range typecheck.InitTodoFunc.Dcl {
dcl.Curfn = fn
}
ni := len(InstrumentGlobalsMap)
if ni != 0 {
// Make an init._ function.
- base.Pos = base.AutogeneratedPos
- name := noder.Renameinit()
- fnInit := typecheck.DeclFunc(name, nil, nil, nil)
+ pos := base.AutogeneratedPos
+ base.Pos = pos
+
+ sym := noder.Renameinit()
+ fnInit := ir.NewFunc(pos, pos, sym, types.NewSignature(nil, nil, nil))
+ typecheck.DeclFunc(fnInit)
// Get an array of instrumented global variables.
globals := instrumentGlobals(fnInit)
return sym.Def.(*ir.Name).Func
}
- base.Pos = base.AutogeneratedPos // less confusing than end of input
+ pos := base.AutogeneratedPos // less confusing than end of input
+ base.Pos = pos
// func sym(p *T, h uintptr) uintptr
- args := []*ir.Field{
- ir.NewField(base.Pos, typecheck.Lookup("p"), types.NewPtr(t)),
- ir.NewField(base.Pos, typecheck.Lookup("h"), types.Types[types.TUINTPTR]),
- }
- results := []*ir.Field{ir.NewField(base.Pos, nil, types.Types[types.TUINTPTR])}
-
- fn := typecheck.DeclFunc(sym, nil, args, results)
+ fn := ir.NewFunc(pos, pos, sym, types.NewSignature(nil,
+ []*types.Field{
+ types.NewField(pos, typecheck.Lookup("p"), types.NewPtr(t)),
+ types.NewField(pos, typecheck.Lookup("h"), types.Types[types.TUINTPTR]),
+ },
+ []*types.Field{
+ types.NewField(pos, nil, types.Types[types.TUINTPTR]),
+ },
+ ))
sym.Def = fn.Nname
fn.Pragma |= ir.Noinline // TODO(mdempsky): We need to emit this during the unified frontend instead, to allow inlining.
- np := fn.Type().Params().Field(0).Nname.(*ir.Name)
- nh := fn.Type().Params().Field(1).Nname.(*ir.Name)
+ params, _ := typecheck.DeclFunc(fn)
+ np := params[0]
+ nh := params[1]
switch t.Kind() {
case types.TARRAY:
if sym.Def != nil {
return sym.Def.(*ir.Name).Func
}
- base.Pos = base.AutogeneratedPos // less confusing than end of input
+
+ pos := base.AutogeneratedPos // less confusing than end of input
+ base.Pos = pos
// func sym(p, q *T) bool
- fn := typecheck.DeclFunc(sym, nil,
- []*ir.Field{ir.NewField(base.Pos, typecheck.Lookup("p"), types.NewPtr(t)), ir.NewField(base.Pos, typecheck.Lookup("q"), types.NewPtr(t))},
- []*ir.Field{ir.NewField(base.Pos, typecheck.Lookup("r"), types.Types[types.TBOOL])},
- )
+ fn := ir.NewFunc(pos, pos, sym, types.NewSignature(nil,
+ []*types.Field{
+ types.NewField(pos, typecheck.Lookup("p"), types.NewPtr(t)),
+ types.NewField(pos, typecheck.Lookup("q"), types.NewPtr(t)),
+ },
+ []*types.Field{
+ types.NewField(pos, typecheck.Lookup("r"), types.Types[types.TBOOL]),
+ },
+ ))
sym.Def = fn.Nname
fn.Pragma |= ir.Noinline // TODO(mdempsky): We need to emit this during the unified frontend instead, to allow inlining.
- np := fn.Type().Params().Field(0).Nname.(*ir.Name)
- nq := fn.Type().Params().Field(1).Nname.(*ir.Name)
- nr := fn.Type().Results().Field(0).Nname.(*ir.Name)
+ params, results := typecheck.DeclFunc(fn)
+ np := params[0]
+ nq := params[1]
+ nr := results[0]
// Label to jump to if an equality test fails.
neq := typecheck.AutoLabel(".neq")
savepos := base.Pos
savedcurfn := ir.CurFunc
- base.Pos = base.AutogeneratedPos
+ pos := base.AutogeneratedPos
+ base.Pos = pos
// At the moment we don't support wrapping a method, we'd need machinery
// below to handle the receiver. Panic if we see this scenario.
}
// Reuse f's types.Sym to create a new ODCLFUNC/function.
- fn := typecheck.DeclFunc(f.Nname.Sym(), nil,
- typecheck.NewFuncParams(ft.Params(), true),
- typecheck.NewFuncParams(ft.Results(), false))
+ // 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().FieldSlice(), true),
+ typecheck.NewFuncParams(ft.Results().FieldSlice(), false)))
fn.ABI = wrapperABI
+ typecheck.DeclFunc(fn)
fn.SetABIWrapper(true)
fn.SetDupok(true)
//
minitsym := typecheck.LookupNum("map.init.", mapinitgen)
mapinitgen++
- newfn := typecheck.DeclFunc(minitsym, nil, nil, nil)
+
+ newfn := ir.NewFunc(base.Pos, base.Pos, minitsym, types.NewSignature(nil, nil, nil))
+ typecheck.DeclFunc(newfn)
if base.Debug.WrapGlobalMapDbg > 0 {
fmt.Fprintf(os.Stderr, "=-= generated func is %v\n", newfn)
}
import (
"fmt"
- "internal/types/errors"
"sync"
"cmd/compile/internal/base"
var funcStack []*ir.Func // stack of previous values of ir.CurFunc
-func DeclFunc(sym *types.Sym, recv *ir.Field, params, results []*ir.Field) *ir.Func {
- fn := ir.NewFunc(base.Pos, base.Pos, sym, nil)
+// DeclFunc creates and returns ONAMEs for the parameters and results
+// of the given function. It also sets ir.CurFunc, and adds fn 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()
- funcStack = append(funcStack, ir.CurFunc)
- ir.CurFunc = fn
-
- var recv1 *types.Field
- if recv != nil {
- recv1 = declareParam(fn, ir.PPARAM, -1, recv)
+ // 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")
}
- typ := types.NewSignature(recv1, declareParams(fn, ir.PPARAM, params), declareParams(fn, ir.PPARAMOUT, results))
- checkdupfields("argument", typ.Recvs().FieldSlice(), typ.Params().FieldSlice(), typ.Results().FieldSlice())
+ params = declareParams(fn, ir.PPARAM, typ.Params().FieldSlice())
+ results = declareParams(fn, ir.PPARAMOUT, typ.Results().FieldSlice())
- fn.Nname.SetType(typ)
- fn.Nname.SetTypecheck(1)
+ funcStack = append(funcStack, ir.CurFunc)
+ ir.CurFunc = fn
fn.Nname.Defn = fn
Target.Funcs = append(Target.Funcs, fn)
- return fn
+ return
}
-// finish the body.
-// called in auto-declaration context.
-// returns in extern-declaration context.
+// FinishFuncBody restores ir.CurFunc to its state before the last
+// call to DeclFunc.
func FinishFuncBody() {
funcStack, ir.CurFunc = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
}
}
}
-// checkdupfields emits errors for duplicately named fields or methods in
-// a list of struct or interface types.
-func checkdupfields(what string, fss ...[]*types.Field) {
- seen := make(map[*types.Sym]bool)
- for _, fs := range fss {
- for _, f := range fs {
- if f.Sym == nil || f.Sym.IsBlank() {
- continue
- }
- if seen[f.Sym] {
- base.ErrorfAt(f.Pos, errors.DuplicateFieldAndMethod, "duplicate %s %s", what, f.Sym.Name)
- continue
- }
- seen[f.Sym] = true
- }
+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 declareParams(fn *ir.Func, ctxt ir.Class, l []*ir.Field) []*types.Field {
- fields := make([]*types.Field, len(l))
- for i, n := range l {
- fields[i] = declareParam(fn, ctxt, i, n)
- }
- return fields
-}
-
-func declareParam(fn *ir.Func, ctxt ir.Class, i int, param *ir.Field) *types.Field {
- f := types.NewField(param.Pos, param.Sym, param.Type)
- f.SetIsDDD(param.IsDDD)
-
+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 {
}
}
- if sym != nil {
- f.Nname = fn.NewLocal(param.Pos, sym, ctxt, f.Type)
+ if sym == nil {
+ return nil
}
- return f
+ name := fn.NewLocal(param.Pos, sym, ctxt, param.Type)
+ param.Nname = name
+ return name
}
// make a new Node off the books.
}
// Given funarg struct list, return list of fn args.
-func NewFuncParams(tl *types.Type, mustname bool) []*ir.Field {
- var args []*ir.Field
- gen := 0
- for _, t := range tl.Fields().Slice() {
- s := t.Sym
+func NewFuncParams(origs []*types.Field, mustname bool) []*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", gen)
- gen++
+ s = LookupNum(".anon", i)
} else if s != nil && s.Pkg != types.LocalPkg {
// TODO(mdempsky): Preserve original position, name, and package.
s = Lookup(s.Name)
}
- a := ir.NewField(base.Pos, s, t.Type)
- a.Pos = t.Pos
- a.IsDDD = t.IsDDD()
- args = append(args, a)
+ p := types.NewField(orig.Pos, s, orig.Type)
+ p.SetIsDDD(orig.IsDDD())
+ res[i] = p
}
-
- return args
+ return res
}
// NodAddr returns a node representing &n at base.Pos.