diff --git a/src/cmd/compile/internal/ir/type.go b/src/cmd/compile/internal/ir/type.go index 00d0a1d634..7db76c1427 100644 --- a/src/cmd/compile/internal/ir/type.go +++ b/src/cmd/compile/internal/ir/type.go @@ -8,31 +8,10 @@ import ( "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 diff --git a/src/cmd/compile/internal/pkginit/init.go b/src/cmd/compile/internal/pkginit/init.go index daf26150a4..4d4896d447 100644 --- a/src/cmd/compile/internal/pkginit/init.go +++ b/src/cmd/compile/internal/pkginit/init.go @@ -28,9 +28,13 @@ func MakeInit() { } // 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 } @@ -113,9 +117,12 @@ func MakeTask() { 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) diff --git a/src/cmd/compile/internal/reflectdata/alg.go b/src/cmd/compile/internal/reflectdata/alg.go index 01135de39f..ba2bf85db3 100644 --- a/src/cmd/compile/internal/reflectdata/alg.go +++ b/src/cmd/compile/internal/reflectdata/alg.go @@ -140,21 +140,25 @@ func hashFunc(t *types.Type) *ir.Func { 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: @@ -365,19 +369,27 @@ func eqFunc(t *types.Type) *ir.Func { 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") diff --git a/src/cmd/compile/internal/ssagen/abi.go b/src/cmd/compile/internal/ssagen/abi.go index 6a6171a0ed..cd01fdacbe 100644 --- a/src/cmd/compile/internal/ssagen/abi.go +++ b/src/cmd/compile/internal/ssagen/abi.go @@ -239,7 +239,8 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) { 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. @@ -250,10 +251,12 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) { } // 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) diff --git a/src/cmd/compile/internal/staticinit/sched.go b/src/cmd/compile/internal/staticinit/sched.go index cc97d2fcf7..52d3d029ad 100644 --- a/src/cmd/compile/internal/staticinit/sched.go +++ b/src/cmd/compile/internal/staticinit/sched.go @@ -1042,7 +1042,9 @@ func tryWrapGlobalMapInit(n ir.Node) (mapvar *ir.Name, genfn *ir.Func, call ir.N // 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) } diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go index 47b975e3b4..a78aad5abc 100644 --- a/src/cmd/compile/internal/typecheck/dcl.go +++ b/src/cmd/compile/internal/typecheck/dcl.go @@ -6,7 +6,6 @@ package typecheck import ( "fmt" - "internal/types/errors" "sync" "cmd/compile/internal/base" @@ -17,32 +16,36 @@ import ( 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() + + // 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().FieldSlice()) + results = declareParams(fn, ir.PPARAMOUT, typ.Results().FieldSlice()) funcStack = append(funcStack, ir.CurFunc) ir.CurFunc = fn - var recv1 *types.Field - if recv != nil { - recv1 = declareParam(fn, ir.PPARAM, -1, recv) - } - - 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()) - - fn.Nname.SetType(typ) - fn.Nname.SetTypecheck(1) - 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] } @@ -53,36 +56,15 @@ func CheckFuncStack() { } } -// 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 { @@ -99,11 +81,13 @@ func declareParam(fn *ir.Func, ctxt ir.Class, i int, param *ir.Field) *types.Fie } } - 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. diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index 91d05778f1..56ff7a7317 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -26,26 +26,22 @@ func LookupNum(prefix string, n int) *types.Sym { } // 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.