Current Path : /usr/local/go/src/cmd/compile/internal/typecheck/ |
Current File : //usr/local/go/src/cmd/compile/internal/typecheck/dcl.go |
// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package typecheck import ( "fmt" "internal/types/errors" "sync" "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/types" "cmd/internal/src" ) var DeclContext ir.Class = ir.PEXTERN // PEXTERN/PAUTO func DeclFunc(sym *types.Sym, recv *ir.Field, params, results []*ir.Field) *ir.Func { fn := ir.NewFunc(base.Pos) fn.Nname = ir.NewNameAt(base.Pos, sym) fn.Nname.Func = fn fn.Nname.Defn = fn ir.MarkFunc(fn.Nname) StartFuncBody(fn) var recv1 *types.Field if recv != nil { recv1 = declareParam(ir.PPARAM, -1, recv) } typ := types.NewSignature(recv1, declareParams(ir.PPARAM, params), declareParams(ir.PPARAMOUT, results)) checkdupfields("argument", typ.Recvs().FieldSlice(), typ.Params().FieldSlice(), typ.Results().FieldSlice()) fn.Nname.SetType(typ) fn.Nname.SetTypecheck(1) return fn } // Declare records that Node n declares symbol n.Sym in the specified // declaration context. func Declare(n *ir.Name, ctxt ir.Class) { if ir.IsBlank(n) { return } s := n.Sym() // kludgy: TypecheckAllowed means we're past parsing. Eg reflectdata.methodWrapper may declare out of package names later. if !inimport && !TypecheckAllowed && s.Pkg != types.LocalPkg { base.ErrorfAt(n.Pos(), 0, "cannot declare name %v", s) } if ctxt == ir.PEXTERN { if s.Name == "init" { base.ErrorfAt(n.Pos(), errors.InvalidInitDecl, "cannot declare init - must be func") } if s.Name == "main" && s.Pkg.Name == "main" { base.ErrorfAt(n.Pos(), errors.InvalidMainDecl, "cannot declare main - must be func") } Target.Externs = append(Target.Externs, n) s.Def = n } else { if ir.CurFunc == nil && ctxt == ir.PAUTO { base.Pos = n.Pos() base.Fatalf("automatic outside function") } if ir.CurFunc != nil && ctxt != ir.PFUNC && n.Op() == ir.ONAME { ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n) } n.Curfn = ir.CurFunc } if ctxt == ir.PAUTO { n.SetFrameOffset(0) } n.Class = ctxt if ctxt == ir.PFUNC { n.Sym().SetFunc(true) } autoexport(n, ctxt) } // Export marks n for export (or reexport). func Export(n *ir.Name) { if n.Sym().OnExportList() { return } n.Sym().SetOnExportList(true) if base.Flag.E != 0 { fmt.Printf("export symbol %v\n", n.Sym()) } Target.Exports = append(Target.Exports, n) } // declare the function proper // and declare the arguments. // called in extern-declaration context // returns in auto-declaration context. func StartFuncBody(fn *ir.Func) { // change the declaration context from extern to auto funcStack = append(funcStack, funcStackEnt{ir.CurFunc, DeclContext}) ir.CurFunc = fn DeclContext = ir.PAUTO } // finish the body. // called in auto-declaration context. // returns in extern-declaration context. func FinishFuncBody() { // change the declaration context from auto to previous context var e funcStackEnt funcStack, e = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1] ir.CurFunc, DeclContext = e.curfn, e.dclcontext } func CheckFuncStack() { if len(funcStack) != 0 { base.Fatalf("funcStack is non-empty: %v", len(funcStack)) } } func autoexport(n *ir.Name, ctxt ir.Class) { if n.Sym().Pkg != types.LocalPkg { return } if (ctxt != ir.PEXTERN && ctxt != ir.PFUNC) || DeclContext != ir.PEXTERN { return } if n.Type() != nil && n.Type().IsKind(types.TFUNC) && ir.IsMethod(n) { return } if types.IsExported(n.Sym().Name) || n.Sym().Name == "init" { Export(n) } if base.Flag.AsmHdr != "" && !n.Sym().Asm() { n.Sym().SetAsm(true) Target.Asms = append(Target.Asms, n) } } // 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 } } } // structs, functions, and methods. // they don't belong here, but where do they belong? func checkembeddedtype(t *types.Type) { if t == nil { return } if t.Sym() == nil && t.IsPtr() { t = t.Elem() if t.IsInterface() { base.Errorf("embedded type cannot be a pointer to interface") } } if t.IsPtr() || t.IsUnsafePtr() { base.Errorf("embedded type cannot be a pointer") } else if t.Kind() == types.TFORW && !t.ForwardType().Embedlineno.IsKnown() { t.ForwardType().Embedlineno = base.Pos } } var funcStack []funcStackEnt // stack of previous values of ir.CurFunc/DeclContext type funcStackEnt struct { curfn *ir.Func dclcontext ir.Class } func declareParams(ctxt ir.Class, l []*ir.Field) []*types.Field { fields := make([]*types.Field, len(l)) for i, n := range l { fields[i] = declareParam(ctxt, i, n) } return fields } func declareParam(ctxt ir.Class, i int, param *ir.Field) *types.Field { f := types.NewField(param.Pos, param.Sym, param.Type) f.SetIsDDD(param.IsDDD) 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 { name := ir.NewNameAt(param.Pos, sym) name.SetType(f.Type) name.SetTypecheck(1) Declare(name, ctxt) f.Nname = name } return f } func Temp(t *types.Type) *ir.Name { return TempAt(base.Pos, ir.CurFunc, t) } // make a new Node off the books. func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name { if curfn == nil { base.Fatalf("no curfn for TempAt") } if curfn.Op() == ir.OCLOSURE { ir.Dump("TempAt", curfn) base.Fatalf("adding TempAt to wrong closure function") } if t == nil { base.Fatalf("TempAt called with nil type") } if t.Kind() == types.TFUNC && t.Recv() != nil { base.Fatalf("misuse of method type: %v", t) } s := &types.Sym{ Name: autotmpname(len(curfn.Dcl)), Pkg: types.LocalPkg, } n := ir.NewNameAt(pos, s) s.Def = n n.SetType(t) n.SetTypecheck(1) n.Class = ir.PAUTO n.SetEsc(ir.EscNever) n.Curfn = curfn n.SetUsed(true) n.SetAutoTemp(true) curfn.Dcl = append(curfn.Dcl, n) types.CalcSize(t) return n } var ( autotmpnamesmu sync.Mutex autotmpnames []string ) // autotmpname returns the name for an autotmp variable numbered n. func autotmpname(n int) string { autotmpnamesmu.Lock() defer autotmpnamesmu.Unlock() // Grow autotmpnames, if needed. if n >= len(autotmpnames) { autotmpnames = append(autotmpnames, make([]string, n+1-len(autotmpnames))...) autotmpnames = autotmpnames[:cap(autotmpnames)] } s := autotmpnames[n] if s == "" { // Give each tmp a different name so that they can be registerized. // Add a preceding . to avoid clashing with legal names. prefix := ".autotmp_%d" s = fmt.Sprintf(prefix, n) autotmpnames[n] = s } return s } // f is method type, with receiver. // return function type, receiver as first argument (or not). func NewMethodType(sig *types.Type, recv *types.Type) *types.Type { nrecvs := 0 if recv != nil { nrecvs++ } // TODO(mdempsky): Move this function to types. // TODO(mdempsky): Preserve positions, names, and package from sig+recv. params := make([]*types.Field, nrecvs+sig.Params().Fields().Len()) if recv != nil { params[0] = types.NewField(base.Pos, nil, recv) } for i, param := range sig.Params().Fields().Slice() { d := types.NewField(base.Pos, nil, param.Type) d.SetIsDDD(param.IsDDD()) params[nrecvs+i] = d } results := make([]*types.Field, sig.Results().Fields().Len()) for i, t := range sig.Results().Fields().Slice() { results[i] = types.NewField(base.Pos, nil, t.Type) } return types.NewSignature(nil, params, results) }