1 // Copyright 2021 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ir"
10 "cmd/compile/internal/syntax"
11 "cmd/compile/internal/typecheck"
12 "cmd/compile/internal/types"
13 "cmd/compile/internal/types2"
16 // TODO(mdempsky): Skip blank declarations? Probably only safe
17 // for declarations without pragmas.
19 func (g *irgen) decls(decls []syntax.Decl) []ir.Node {
21 for _, decl := range decls {
22 switch decl := decl.(type) {
23 case *syntax.ConstDecl:
24 g.constDecl(&res, decl)
25 case *syntax.FuncDecl:
26 g.funcDecl(&res, decl)
27 case *syntax.TypeDecl:
28 if ir.CurFunc == nil {
29 continue // already handled in irgen.generate
31 g.typeDecl(&res, decl)
35 g.unhandled("declaration", decl)
41 func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) {
42 // TODO(mdempsky): Merge with gcimports so we don't have to import
45 g.pragmaFlags(decl.Pragma, 0)
47 ipkg := importfile(decl)
48 if ipkg == ir.Pkgs.Unsafe {
49 p.importedUnsafe = true
53 func (g *irgen) constDecl(out *ir.Nodes, decl *syntax.ConstDecl) {
54 g.pragmaFlags(decl.Pragma, 0)
56 for _, name := range decl.NameList {
57 name, obj := g.def(name)
58 name.SetVal(obj.(*types2.Const).Val())
59 out.Append(ir.NewDecl(g.pos(decl), ir.ODCLCONST, name))
63 func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
64 fn := ir.NewFunc(g.pos(decl))
65 fn.Nname, _ = g.def(decl.Name)
69 fn.Pragma = g.pragmaFlags(decl.Pragma, funcPragmas)
70 if fn.Pragma&ir.Systemstack != 0 && fn.Pragma&ir.Nosplit != 0 {
71 base.ErrorfAt(fn.Pos(), "go:nosplit and go:systemstack cannot be combined")
74 if decl.Name.Value == "init" && decl.Recv == nil {
75 g.target.Inits = append(g.target.Inits, fn)
78 g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
83 func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
85 if !types.AllowsGoVersion(types.LocalPkg, 1, 9) {
86 base.ErrorfAt(g.pos(decl), "type aliases only supported as of -lang=go1.9")
89 name, _ := g.def(decl.Name)
90 g.pragmaFlags(decl.Pragma, 0)
92 // TODO(mdempsky): This matches how typecheckdef marks aliases for
93 // export, but this won't generalize to exporting function-scoped
94 // type aliases. We should maybe just use n.Alias() instead.
95 if ir.CurFunc == nil {
96 name.Sym().Def = ir.TypeNode(name.Type())
99 out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
103 // Prevent size calculations until we set the underlying type.
104 types.DeferCheckSize()
106 name, obj := g.def(decl.Name)
107 ntyp, otyp := name.Type(), obj.Type()
108 if ir.CurFunc != nil {
110 ntyp.Vargen = typecheck.TypeGen
113 pragmas := g.pragmaFlags(decl.Pragma, typePragmas)
114 name.SetPragma(pragmas) // TODO(mdempsky): Is this still needed?
116 if pragmas&ir.NotInHeap != 0 {
117 ntyp.SetNotInHeap(true)
120 // We need to use g.typeExpr(decl.Type) here to ensure that for
121 // chained, defined-type declarations like
126 // type U struct { … }
128 // that we mark both T and U as NotInHeap. If we instead used just
129 // g.typ(otyp.Underlying()), then we'd instead set T's underlying
130 // type directly to the struct type (which is not marked NotInHeap)
131 // and fail to mark T as NotInHeap.
133 // Also, we rely here on Type.SetUnderlying allowing passing a
134 // defined type and handling forward references like from T to U
135 // above. Contrast with go/types's Named.SetUnderlying, which
138 // [mdempsky: Subtleties like these are why I always vehemently
139 // object to new type pragmas.]
140 ntyp.SetUnderlying(g.typeExpr(decl.Type))
141 types.ResumeCheckSize()
143 if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 {
144 methods := make([]*types.Field, otyp.NumMethods())
145 for i := range methods {
148 methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
149 methods[i].Nname = meth
151 ntyp.Methods().Set(methods)
154 out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
157 func (g *irgen) varDecl(out *ir.Nodes, decl *syntax.VarDecl) {
159 names := make([]*ir.Name, len(decl.NameList))
160 for i, name := range decl.NameList {
161 names[i], _ = g.def(name)
163 values := g.exprList(decl.Values)
165 if decl.Pragma != nil {
166 pragma := decl.Pragma.(*pragmas)
167 if err := varEmbed(g.makeXPos, names[0], decl, pragma); err != nil {
168 base.ErrorfAt(g.pos(decl), "%s", err.Error())
170 g.reportUnused(pragma)
173 var as2 *ir.AssignListStmt
174 if len(values) != 0 && len(names) != len(values) {
175 as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values)
178 for i, name := range names {
179 if ir.CurFunc != nil {
180 out.Append(ir.NewDecl(pos, ir.ODCL, name))
186 as := ir.NewAssignStmt(pos, name, nil)
187 if len(values) != 0 {
190 } else if ir.CurFunc == nil {
193 out.Append(typecheck.Stmt(as))
197 out.Append(typecheck.Stmt(as2))
201 // pragmaFlags returns any specified pragma flags included in allowed,
202 // and reports errors about any other, unexpected pragmas.
203 func (g *irgen) pragmaFlags(pragma syntax.Pragma, allowed ir.PragmaFlag) ir.PragmaFlag {
207 p := pragma.(*pragmas)
208 present := p.Flag & allowed
214 // reportUnused reports errors about any unused pragmas.
215 func (g *irgen) reportUnused(pragma *pragmas) {
216 for _, pos := range pragma.Pos {
217 if pos.Flag&pragma.Flag != 0 {
218 base.ErrorfAt(g.makeXPos(pos.Pos), "misplaced compiler directive")
221 if len(pragma.Embeds) > 0 {
222 for _, e := range pragma.Embeds {
223 base.ErrorfAt(g.makeXPos(e.Pos), "misplaced go:embed directive")