diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/dcl.go')
-rw-r--r-- | src/cmd/compile/internal/gc/dcl.go | 580 |
1 files changed, 4 insertions, 576 deletions
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index 1189d0ec12..e53bba44ad 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -8,11 +8,11 @@ import ( "bytes" "cmd/compile/internal/base" "cmd/compile/internal/ir" + "cmd/compile/internal/typecheck" "cmd/compile/internal/types" "cmd/internal/obj" "cmd/internal/src" "fmt" - "strings" ) func EnableNoWriteBarrierRecCheck() { @@ -28,154 +28,6 @@ func NoWriteBarrierRecCheck() { var nowritebarrierrecCheck *nowritebarrierrecChecker -// redeclare emits a diagnostic about symbol s being redeclared at pos. -func redeclare(pos src.XPos, s *types.Sym, where string) { - if !s.Lastlineno.IsKnown() { - pkgName := dotImportRefs[s.Def.(*ir.Ident)] - base.ErrorfAt(pos, "%v redeclared %s\n"+ - "\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path) - } else { - prevPos := s.Lastlineno - - // When an import and a declaration collide in separate files, - // present the import as the "redeclared", because the declaration - // is visible where the import is, but not vice versa. - // See issue 4510. - if s.Def == nil { - pos, prevPos = prevPos, pos - } - - base.ErrorfAt(pos, "%v redeclared %s\n"+ - "\t%v: previous declaration", s, where, base.FmtPos(prevPos)) - } -} - -var vargen int - -// declare individual names - var, typ, const - -var declare_typegen int - -// 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: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later. - if !inimport && !typecheckok && s.Pkg != types.LocalPkg { - base.ErrorfAt(n.Pos(), "cannot declare name %v", s) - } - - gen := 0 - if ctxt == ir.PEXTERN { - if s.Name == "init" { - base.ErrorfAt(n.Pos(), "cannot declare init - must be func") - } - if s.Name == "main" && s.Pkg.Name == "main" { - base.ErrorfAt(n.Pos(), "cannot declare main - must be func") - } - Target.Externs = append(Target.Externs, 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) - } - if n.Op() == ir.OTYPE { - declare_typegen++ - gen = declare_typegen - } else if n.Op() == ir.ONAME && ctxt == ir.PAUTO && !strings.Contains(s.Name, "·") { - vargen++ - gen = vargen - } - types.Pushdcl(s) - n.Curfn = ir.CurFunc - } - - if ctxt == ir.PAUTO { - n.SetFrameOffset(0) - } - - if s.Block == types.Block { - // functype will print errors about duplicate function arguments. - // Don't repeat the error here. - if ctxt != ir.PPARAM && ctxt != ir.PPARAMOUT { - redeclare(n.Pos(), s, "in this block") - } - } - - s.Block = types.Block - s.Lastlineno = base.Pos - s.Def = n - n.Vargen = int32(gen) - n.Class_ = ctxt - if ctxt == ir.PFUNC { - n.Sym().SetFunc(true) - } - - autoexport(n, ctxt) -} - -// declare variables from grammar -// new_name_list (type | [type] = expr_list) -func variter(vl []*ir.Name, t ir.Ntype, el []ir.Node) []ir.Node { - var init []ir.Node - doexpr := len(el) > 0 - - if len(el) == 1 && len(vl) > 1 { - e := el[0] - as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil) - as2.Rhs = []ir.Node{e} - for _, v := range vl { - as2.Lhs.Append(v) - declare(v, dclcontext) - v.Ntype = t - v.Defn = as2 - if ir.CurFunc != nil { - init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v)) - } - } - - return append(init, as2) - } - - for i, v := range vl { - var e ir.Node - if doexpr { - if i >= len(el) { - base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el)) - break - } - e = el[i] - } - - declare(v, dclcontext) - v.Ntype = t - - if e != nil || ir.CurFunc != nil || ir.IsBlank(v) { - if ir.CurFunc != nil { - init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v)) - } - as := ir.NewAssignStmt(base.Pos, v, e) - init = append(init, as) - if e != nil { - v.Defn = as - } - } - } - - if len(el) > len(vl) { - base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el)) - } - return init -} - // oldname returns the Node that declares symbol s in the current scope. // If no such Node currently exists, an ONONAME Node is returned instead. // Automatically creates a new closure variable if the referenced symbol was @@ -204,7 +56,7 @@ func oldname(s *types.Sym) ir.Node { c := n.Name().Innermost if c == nil || c.Curfn != ir.CurFunc { // Do not have a closure var for the active closure yet; make one. - c = NewName(s) + c = typecheck.NewName(s) c.Class_ = ir.PAUTOHEAP c.SetIsClosureVar(true) c.SetIsDDD(n.IsDDD()) @@ -236,419 +88,10 @@ func importName(sym *types.Sym) ir.Node { return n } -// := declarations -func colasname(n ir.Node) bool { - switch n.Op() { - case ir.ONAME, - ir.ONONAME, - ir.OPACK, - ir.OTYPE, - ir.OLITERAL: - return n.Sym() != nil - } - - return false -} - -func colasdefn(left []ir.Node, defn ir.Node) { - for _, n := range left { - if n.Sym() != nil { - n.Sym().SetUniq(true) - } - } - - var nnew, nerr int - for i, n := range left { - if ir.IsBlank(n) { - continue - } - if !colasname(n) { - base.ErrorfAt(defn.Pos(), "non-name %v on left side of :=", n) - nerr++ - continue - } - - if !n.Sym().Uniq() { - base.ErrorfAt(defn.Pos(), "%v repeated on left side of :=", n.Sym()) - n.SetDiag(true) - nerr++ - continue - } - - n.Sym().SetUniq(false) - if n.Sym().Block == types.Block { - continue - } - - nnew++ - n := NewName(n.Sym()) - declare(n, dclcontext) - n.Defn = defn - defn.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n)) - left[i] = n - } - - if nnew == 0 && nerr == 0 { - base.ErrorfAt(defn.Pos(), "no new variables on left side of :=") - } -} - -// declare the function proper -// and declare the arguments. -// called in extern-declaration context -// returns in auto-declaration context. -func funchdr(fn *ir.Func) { - // change the declaration context from extern to auto - funcStack = append(funcStack, funcStackEnt{ir.CurFunc, dclcontext}) - ir.CurFunc = fn - dclcontext = ir.PAUTO - - types.Markdcl() - - if fn.Nname.Ntype != nil { - funcargs(fn.Nname.Ntype.(*ir.FuncType)) - } else { - funcargs2(fn.Type()) - } -} - -func funcargs(nt *ir.FuncType) { - if nt.Op() != ir.OTFUNC { - base.Fatalf("funcargs %v", nt.Op()) - } - - // re-start the variable generation number - // we want to use small numbers for the return variables, - // so let them have the chunk starting at 1. - // - // TODO(mdempsky): This is ugly, and only necessary because - // esc.go uses Vargen to figure out result parameters' index - // within the result tuple. - vargen = len(nt.Results) - - // declare the receiver and in arguments. - if nt.Recv != nil { - funcarg(nt.Recv, ir.PPARAM) - } - for _, n := range nt.Params { - funcarg(n, ir.PPARAM) - } - - oldvargen := vargen - vargen = 0 - - // declare the out arguments. - gen := len(nt.Params) - for _, n := range nt.Results { - if n.Sym == nil { - // Name so that escape analysis can track it. ~r stands for 'result'. - n.Sym = lookupN("~r", gen) - gen++ - } - if n.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. - n.Sym = lookupN("~b", gen) - gen++ - } - - funcarg(n, ir.PPARAMOUT) - } - - vargen = oldvargen -} - -func funcarg(n *ir.Field, ctxt ir.Class) { - if n.Sym == nil { - return - } - - name := ir.NewNameAt(n.Pos, n.Sym) - n.Decl = name - name.Ntype = n.Ntype - name.SetIsDDD(n.IsDDD) - declare(name, ctxt) - - vargen++ - n.Decl.Vargen = int32(vargen) -} - -// Same as funcargs, except run over an already constructed TFUNC. -// This happens during import, where the hidden_fndcl rule has -// used functype directly to parse the function's type. -func funcargs2(t *types.Type) { - if t.Kind() != types.TFUNC { - base.Fatalf("funcargs2 %v", t) - } - - for _, f := range t.Recvs().Fields().Slice() { - funcarg2(f, ir.PPARAM) - } - for _, f := range t.Params().Fields().Slice() { - funcarg2(f, ir.PPARAM) - } - for _, f := range t.Results().Fields().Slice() { - funcarg2(f, ir.PPARAMOUT) - } -} - -func funcarg2(f *types.Field, ctxt ir.Class) { - if f.Sym == nil { - return - } - n := ir.NewNameAt(f.Pos, f.Sym) - f.Nname = n - n.SetType(f.Type) - n.SetIsDDD(f.IsDDD()) - declare(n, ctxt) -} - -var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext - -type funcStackEnt struct { - curfn *ir.Func - dclcontext ir.Class -} - -func CheckFuncStack() { - if len(funcStack) != 0 { - base.Fatalf("funcStack is non-empty: %v", len(funcStack)) - } -} - -// finish the body. -// called in auto-declaration context. -// returns in extern-declaration context. -func funcbody() { - // change the declaration context from auto to previous context - types.Popdcl() - var e funcStackEnt - funcStack, e = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1] - ir.CurFunc, dclcontext = e.curfn, e.dclcontext -} - -// 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 - } -} - -// 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, "duplicate %s %s", what, f.Sym.Name) - continue - } - seen[f.Sym] = true - } - } -} - -// convert a parsed id/type list into -// a type for struct/interface/arglist -func tostruct(l []*ir.Field) *types.Type { - lno := base.Pos - - fields := make([]*types.Field, len(l)) - for i, n := range l { - base.Pos = n.Pos - - if n.Ntype != nil { - n.Type = typecheckNtype(n.Ntype).Type() - n.Ntype = nil - } - f := types.NewField(n.Pos, n.Sym, n.Type) - if n.Embedded { - checkembeddedtype(n.Type) - f.Embedded = 1 - } - f.Note = n.Note - fields[i] = f - } - checkdupfields("field", fields) - - base.Pos = lno - return types.NewStruct(types.LocalPkg, fields) -} - -func tointerface(nmethods []*ir.Field) *types.Type { - if len(nmethods) == 0 { - return types.Types[types.TINTER] - } - - lno := base.Pos - - methods := make([]*types.Field, len(nmethods)) - for i, n := range nmethods { - base.Pos = n.Pos - if n.Ntype != nil { - n.Type = typecheckNtype(n.Ntype).Type() - n.Ntype = nil - } - methods[i] = types.NewField(n.Pos, n.Sym, n.Type) - } - - base.Pos = lno - return types.NewInterface(types.LocalPkg, methods) -} - func fakeRecv() *ir.Field { return ir.NewField(base.Pos, nil, nil, types.FakeRecvType()) } -func fakeRecvField() *types.Field { - return types.NewField(src.NoXPos, nil, types.FakeRecvType()) -} - -// turn a parsed function declaration into a type -func functype(nrecv *ir.Field, nparams, nresults []*ir.Field) *types.Type { - funarg := func(n *ir.Field) *types.Field { - lno := base.Pos - base.Pos = n.Pos - - if n.Ntype != nil { - n.Type = typecheckNtype(n.Ntype).Type() - n.Ntype = nil - } - - f := types.NewField(n.Pos, n.Sym, n.Type) - f.SetIsDDD(n.IsDDD) - if n.Decl != nil { - n.Decl.SetType(f.Type) - f.Nname = n.Decl - } - - base.Pos = lno - return f - } - funargs := func(nn []*ir.Field) []*types.Field { - res := make([]*types.Field, len(nn)) - for i, n := range nn { - res[i] = funarg(n) - } - return res - } - - var recv *types.Field - if nrecv != nil { - recv = funarg(nrecv) - } - - t := types.NewSignature(types.LocalPkg, recv, funargs(nparams), funargs(nresults)) - checkdupfields("argument", t.Recvs().FieldSlice(), t.Params().FieldSlice(), t.Results().FieldSlice()) - return t -} - -// Add a method, declared as a function. -// - msym is the method symbol -// - t is function type (with receiver) -// Returns a pointer to the existing or added Field; or nil if there's an error. -func addmethod(n *ir.Func, msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field { - if msym == nil { - base.Fatalf("no method symbol") - } - - // get parent type sym - rf := t.Recv() // ptr to this structure - if rf == nil { - base.Errorf("missing receiver") - return nil - } - - mt := types.ReceiverBaseType(rf.Type) - if mt == nil || mt.Sym() == nil { - pa := rf.Type - t := pa - if t != nil && t.IsPtr() { - if t.Sym() != nil { - base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t) - return nil - } - t = t.Elem() - } - - switch { - case t == nil || t.Broke(): - // rely on typecheck having complained before - case t.Sym() == nil: - base.Errorf("invalid receiver type %v (%v is not a defined type)", pa, t) - case t.IsPtr(): - base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t) - case t.IsInterface(): - base.Errorf("invalid receiver type %v (%v is an interface type)", pa, t) - default: - // Should have picked off all the reasons above, - // but just in case, fall back to generic error. - base.Errorf("invalid receiver type %v (%L / %L)", pa, pa, t) - } - return nil - } - - if local && mt.Sym().Pkg != types.LocalPkg { - base.Errorf("cannot define new methods on non-local type %v", mt) - return nil - } - - if msym.IsBlank() { - return nil - } - - if mt.IsStruct() { - for _, f := range mt.Fields().Slice() { - if f.Sym == msym { - base.Errorf("type %v has both field and method named %v", mt, msym) - f.SetBroke(true) - return nil - } - } - } - - for _, f := range mt.Methods().Slice() { - if msym.Name != f.Sym.Name { - continue - } - // types.Identical only checks that incoming and result parameters match, - // so explicitly check that the receiver parameters match too. - if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) { - base.Errorf("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t) - } - return f - } - - f := types.NewField(base.Pos, msym, t) - f.Nname = n.Nname - f.SetNointerface(nointerface) - - mt.Methods().Append(f) - return f -} - // funcsym returns s·f. func funcsym(s *types.Sym) *types.Sym { // funcsymsmu here serves to protect not just mutations of funcsyms (below), @@ -700,21 +143,6 @@ func makefuncsym(s *types.Sym) { } } -func dclfunc(sym *types.Sym, tfn ir.Ntype) *ir.Func { - if tfn.Op() != ir.OTFUNC { - base.Fatalf("expected OTFUNC node, got %v", tfn) - } - - fn := ir.NewFunc(base.Pos) - fn.Nname = ir.NewFuncNameAt(base.Pos, sym, fn) - fn.Nname.Defn = fn - fn.Nname.Ntype = tfn - ir.MarkFunc(fn.Nname) - funchdr(fn) - fn.Nname.Ntype = typecheckNtype(fn.Nname.Ntype) - return fn -} - type nowritebarrierrecChecker struct { // extraCalls contains extra function calls that may not be // visible during later analysis. It maps from the ODCLFUNC of @@ -742,7 +170,7 @@ func newNowritebarrierrecChecker() *nowritebarrierrecChecker { // important to handle it for this check, so we model it // directly. This has to happen before transformclosure since // it's a lot harder to work out the argument after. - for _, n := range Target.Decls { + for _, n := range typecheck.Target.Decls { if n.Op() != ir.ODCLFUNC { continue } @@ -819,7 +247,7 @@ func (c *nowritebarrierrecChecker) check() { // q is the queue of ODCLFUNC Nodes to visit in BFS order. var q ir.NameQueue - for _, n := range Target.Decls { + for _, n := range typecheck.Target.Decls { if n.Op() != ir.ODCLFUNC { continue } |