aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/gc/dcl.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/gc/dcl.go')
-rw-r--r--src/cmd/compile/internal/gc/dcl.go580
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
}