// TODO(mdempsky): Skip blank declarations? Probably only safe
// for declarations without pragmas.
-func (g *irgen) decls(decls []syntax.Decl) []ir.Node {
- var res ir.Nodes
+func (g *irgen) decls(res *ir.Nodes, decls []syntax.Decl) {
for _, decl := range decls {
switch decl := decl.(type) {
case *syntax.ConstDecl:
- g.constDecl(&res, decl)
+ g.constDecl(res, decl)
case *syntax.FuncDecl:
- g.funcDecl(&res, decl)
+ g.funcDecl(res, decl)
case *syntax.TypeDecl:
if ir.CurFunc == nil {
continue // already handled in irgen.generate
}
- g.typeDecl(&res, decl)
+ g.typeDecl(res, decl)
case *syntax.VarDecl:
- g.varDecl(&res, decl)
+ g.varDecl(res, decl)
default:
g.unhandled("declaration", decl)
}
}
- return res
}
func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) {
g.target.Inits = append(g.target.Inits, fn)
}
- if fn.Type().HasTParam() {
- g.topFuncIsGeneric = true
- }
- g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
- g.topFuncIsGeneric = false
- if fn.Type().HasTParam() && fn.Body != nil {
- // Set pointers to the dcls/body of a generic function/method in
- // the Inl struct, so it is marked for export, is available for
- // stenciling, and works with Inline_Flood().
- fn.Inl = &ir.Inline{
- Cost: 1,
- Dcl: fn.Dcl,
- Body: fn.Body,
+ g.later(func() {
+ if fn.Type().HasTParam() {
+ g.topFuncIsGeneric = true
+ }
+ g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
+ g.topFuncIsGeneric = false
+ if fn.Type().HasTParam() && fn.Body != nil {
+ // Set pointers to the dcls/body of a generic function/method in
+ // the Inl struct, so it is marked for export, is available for
+ // stenciling, and works with Inline_Flood().
+ fn.Inl = &ir.Inline{
+ Cost: 1,
+ Dcl: fn.Dcl,
+ Body: fn.Body,
+ }
}
- }
- out.Append(fn)
+ out.Append(fn)
+ })
}
func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
for i, name := range decl.NameList {
names[i], _ = g.def(name)
}
- values := g.exprList(decl.Values)
if decl.Pragma != nil {
pragma := decl.Pragma.(*pragmas)
g.reportUnused(pragma)
}
- var as2 *ir.AssignListStmt
- if len(values) != 0 && len(names) != len(values) {
- as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values)
- }
+ do := func() {
+ values := g.exprList(decl.Values)
- for i, name := range names {
- if ir.CurFunc != nil {
- out.Append(ir.NewDecl(pos, ir.ODCL, name))
+ var as2 *ir.AssignListStmt
+ if len(values) != 0 && len(names) != len(values) {
+ as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values)
}
- if as2 != nil {
- as2.Lhs[i] = name
- name.Defn = as2
- } else {
- as := ir.NewAssignStmt(pos, name, nil)
- if len(values) != 0 {
- as.Y = values[i]
- name.Defn = as
- } else if ir.CurFunc == nil {
- name.Defn = as
- }
- lhs := []ir.Node{as.X}
- rhs := []ir.Node{}
- if as.Y != nil {
- rhs = []ir.Node{as.Y}
+
+ for i, name := range names {
+ if ir.CurFunc != nil {
+ out.Append(ir.NewDecl(pos, ir.ODCL, name))
}
- transformAssign(as, lhs, rhs)
- as.X = lhs[0]
- if as.Y != nil {
- as.Y = rhs[0]
+ if as2 != nil {
+ as2.Lhs[i] = name
+ name.Defn = as2
+ } else {
+ as := ir.NewAssignStmt(pos, name, nil)
+ if len(values) != 0 {
+ as.Y = values[i]
+ name.Defn = as
+ } else if ir.CurFunc == nil {
+ name.Defn = as
+ }
+ lhs := []ir.Node{as.X}
+ rhs := []ir.Node{}
+ if as.Y != nil {
+ rhs = []ir.Node{as.Y}
+ }
+ transformAssign(as, lhs, rhs)
+ as.X = lhs[0]
+ if as.Y != nil {
+ as.Y = rhs[0]
+ }
+ as.SetTypecheck(1)
+ out.Append(as)
}
- as.SetTypecheck(1)
- out.Append(as)
+ }
+ if as2 != nil {
+ transformAssign(as2, as2.Lhs, as2.Rhs)
+ as2.SetTypecheck(1)
+ out.Append(as2)
}
}
- if as2 != nil {
- transformAssign(as2, as2.Lhs, as2.Rhs)
- as2.SetTypecheck(1)
- out.Append(as2)
+
+ // If we're within a function, we need to process the assignment
+ // part of the variable declaration right away. Otherwise, we leave
+ // it to be handled after all top-level declarations are processed.
+ if ir.CurFunc != nil {
+ do()
+ } else {
+ g.later(do)
}
}
typs map[types2.Type]*types.Type
marker dwarfgen.ScopeMarker
+ // laterFuncs records tasks that need to run after all declarations
+ // are processed.
+ laterFuncs []func()
+
+ // exprStmtOK indicates whether it's safe to generate expressions or
+ // statements yet.
+ exprStmtOK bool
+
// Fully-instantiated generic types whose methods should be instantiated
instTypeList []*types.Type
topFuncIsGeneric bool
}
+func (g *irgen) later(fn func()) {
+ g.laterFuncs = append(g.laterFuncs, fn)
+}
+
type delayInfo struct {
gf *ir.Name
targs []*types.Type
// At this point, types2 has already handled name resolution and
// type checking. We just need to map from its object and type
// representations to those currently used by the rest of the
- // compiler. This happens mostly in 3 passes.
+ // compiler. This happens in a few passes.
// 1. Process all import declarations. We use the compiler's own
// importer for this, rather than types2's gcimporter-derived one,
// 3. Process all remaining declarations.
for _, declList := range declLists {
- g.target.Decls = append(g.target.Decls, g.decls(declList)...)
+ g.decls((*ir.Nodes)(&g.target.Decls), declList)
+ }
+ g.exprStmtOK = true
+
+ // 4. Run any "later" tasks. Avoid using 'range' so that tasks can
+ // recursively queue further tasks. (Not currently utilized though.)
+ for len(g.laterFuncs) > 0 {
+ fn := g.laterFuncs[0]
+ g.laterFuncs = g.laterFuncs[1:]
+ fn()
}
if base.Flag.W > 1 {
}
}
g.target.Decls = g.target.Decls[:j]
+
+ base.Assertf(len(g.laterFuncs) == 0, "still have %d later funcs", len(g.laterFuncs))
}
func (g *irgen) unhandled(what string, p poser) {