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. 4 5package noder 6 7import ( 8 "go/constant" 9 10 "cmd/compile/internal/base" 11 "cmd/compile/internal/ir" 12 "cmd/compile/internal/syntax" 13 "cmd/compile/internal/typecheck" 14 "cmd/compile/internal/types" 15 "cmd/compile/internal/types2" 16) 17 18// TODO(mdempsky): Skip blank declarations? Probably only safe 19// for declarations without pragmas. 20 21func (g *irgen) decls(res *ir.Nodes, decls []syntax.Decl) { 22 for _, decl := range decls { 23 switch decl := decl.(type) { 24 case *syntax.ConstDecl: 25 g.constDecl(res, decl) 26 case *syntax.FuncDecl: 27 g.funcDecl(res, decl) 28 case *syntax.TypeDecl: 29 if ir.CurFunc == nil { 30 continue // already handled in irgen.generate 31 } 32 g.typeDecl(res, decl) 33 case *syntax.VarDecl: 34 g.varDecl(res, decl) 35 default: 36 g.unhandled("declaration", decl) 37 } 38 } 39} 40 41func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) { 42 g.pragmaFlags(decl.Pragma, 0) 43 44 // Get the imported package's path, as resolved already by types2 45 // and gcimporter. This is the same path as would be computed by 46 // parseImportPath. 47 switch pkgNameOf(g.info, decl).Imported().Path() { 48 case "unsafe": 49 p.importedUnsafe = true 50 case "embed": 51 p.importedEmbed = true 52 } 53} 54 55// pkgNameOf returns the PkgName associated with the given ImportDecl. 56func pkgNameOf(info *types2.Info, decl *syntax.ImportDecl) *types2.PkgName { 57 if name := decl.LocalPkgName; name != nil { 58 return info.Defs[name].(*types2.PkgName) 59 } 60 return info.Implicits[decl].(*types2.PkgName) 61} 62 63func (g *irgen) constDecl(out *ir.Nodes, decl *syntax.ConstDecl) { 64 g.pragmaFlags(decl.Pragma, 0) 65 66 for _, name := range decl.NameList { 67 name, obj := g.def(name) 68 69 // For untyped numeric constants, make sure the value 70 // representation matches what the rest of the 71 // compiler (really just iexport) expects. 72 // TODO(mdempsky): Revisit after #43891 is resolved. 73 val := obj.(*types2.Const).Val() 74 switch name.Type() { 75 case types.UntypedInt, types.UntypedRune: 76 val = constant.ToInt(val) 77 case types.UntypedFloat: 78 val = constant.ToFloat(val) 79 case types.UntypedComplex: 80 val = constant.ToComplex(val) 81 } 82 name.SetVal(val) 83 84 out.Append(ir.NewDecl(g.pos(decl), ir.ODCLCONST, name)) 85 } 86} 87 88func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) { 89 assert(g.curDecl == "") 90 // Set g.curDecl to the function name, as context for the type params declared 91 // during types2-to-types1 translation if this is a generic function. 92 g.curDecl = decl.Name.Value 93 obj2 := g.info.Defs[decl.Name] 94 recv := types2.AsSignature(obj2.Type()).Recv() 95 if recv != nil { 96 t2 := deref2(recv.Type()) 97 // This is a method, so set g.curDecl to recvTypeName.methName instead. 98 g.curDecl = t2.(*types2.Named).Obj().Name() + "." + g.curDecl 99 } 100 101 fn := ir.NewFunc(g.pos(decl)) 102 fn.Nname, _ = g.def(decl.Name) 103 fn.Nname.Func = fn 104 fn.Nname.Defn = fn 105 106 fn.Pragma = g.pragmaFlags(decl.Pragma, funcPragmas) 107 if fn.Pragma&ir.Systemstack != 0 && fn.Pragma&ir.Nosplit != 0 { 108 base.ErrorfAt(fn.Pos(), "go:nosplit and go:systemstack cannot be combined") 109 } 110 if fn.Pragma&ir.Nointerface != 0 { 111 // Propagate //go:nointerface from Func.Pragma to Field.Nointerface. 112 // This is a bit roundabout, but this is the earliest point where we've 113 // processed the function's pragma flags, and we've also already created 114 // the Fields to represent the receiver's method set. 115 if recv := fn.Type().Recv(); recv != nil { 116 typ := types.ReceiverBaseType(recv.Type) 117 if typ.OrigSym() != nil { 118 // For a generic method, we mark the methods on the 119 // base generic type, since those are the methods 120 // that will be stenciled. 121 typ = typ.OrigSym().Def.Type() 122 } 123 meth := typecheck.Lookdot1(fn, typecheck.Lookup(decl.Name.Value), typ, typ.Methods(), 0) 124 meth.SetNointerface(true) 125 } 126 } 127 128 if decl.Body != nil && fn.Pragma&ir.Noescape != 0 { 129 base.ErrorfAt(fn.Pos(), "can only use //go:noescape with external func implementations") 130 } 131 132 if decl.Name.Value == "init" && decl.Recv == nil { 133 g.target.Inits = append(g.target.Inits, fn) 134 } 135 136 haveEmbed := g.haveEmbed 137 g.curDecl = "" 138 g.later(func() { 139 defer func(b bool) { g.haveEmbed = b }(g.haveEmbed) 140 141 g.haveEmbed = haveEmbed 142 if fn.Type().HasTParam() { 143 g.topFuncIsGeneric = true 144 } 145 g.funcBody(fn, decl.Recv, decl.Type, decl.Body) 146 g.topFuncIsGeneric = false 147 if fn.Type().HasTParam() && fn.Body != nil { 148 // Set pointers to the dcls/body of a generic function/method in 149 // the Inl struct, so it is marked for export, is available for 150 // stenciling, and works with Inline_Flood(). 151 fn.Inl = &ir.Inline{ 152 Cost: 1, 153 Dcl: fn.Dcl, 154 Body: fn.Body, 155 } 156 } 157 158 out.Append(fn) 159 }) 160} 161 162func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) { 163 // Set the position for any error messages we might print (e.g. too large types). 164 base.Pos = g.pos(decl) 165 assert(g.curDecl == "") 166 // Set g.curDecl to the type name, as context for the type params declared 167 // during types2-to-types1 translation if this is a generic type. 168 g.curDecl = decl.Name.Value 169 if decl.Alias { 170 name, _ := g.def(decl.Name) 171 g.pragmaFlags(decl.Pragma, 0) 172 assert(name.Alias()) // should be set by irgen.obj 173 174 out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name)) 175 g.curDecl = "" 176 return 177 } 178 179 // Prevent size calculations until we set the underlying type. 180 types.DeferCheckSize() 181 182 name, obj := g.def(decl.Name) 183 ntyp, otyp := name.Type(), obj.Type() 184 if ir.CurFunc != nil { 185 ntyp.SetVargen() 186 } 187 188 pragmas := g.pragmaFlags(decl.Pragma, typePragmas) 189 name.SetPragma(pragmas) // TODO(mdempsky): Is this still needed? 190 191 if pragmas&ir.NotInHeap != 0 { 192 ntyp.SetNotInHeap(true) 193 } 194 195 // We need to use g.typeExpr(decl.Type) here to ensure that for 196 // chained, defined-type declarations like: 197 // 198 // type T U 199 // 200 // //go:notinheap 201 // type U struct { … } 202 // 203 // we mark both T and U as NotInHeap. If we instead used just 204 // g.typ(otyp.Underlying()), then we'd instead set T's underlying 205 // type directly to the struct type (which is not marked NotInHeap) 206 // and fail to mark T as NotInHeap. 207 // 208 // Also, we rely here on Type.SetUnderlying allowing passing a 209 // defined type and handling forward references like from T to U 210 // above. Contrast with go/types's Named.SetUnderlying, which 211 // disallows this. 212 // 213 // [mdempsky: Subtleties like these are why I always vehemently 214 // object to new type pragmas.] 215 ntyp.SetUnderlying(g.typeExpr(decl.Type)) 216 217 tparams := otyp.(*types2.Named).TypeParams() 218 if n := tparams.Len(); n > 0 { 219 rparams := make([]*types.Type, n) 220 for i := range rparams { 221 rparams[i] = g.typ(tparams.At(i)) 222 } 223 // This will set hasTParam flag if any rparams are not concrete types. 224 ntyp.SetRParams(rparams) 225 } 226 types.ResumeCheckSize() 227 228 g.curDecl = "" 229 if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 { 230 methods := make([]*types.Field, otyp.NumMethods()) 231 for i := range methods { 232 m := otyp.Method(i) 233 // Set g.curDecl to recvTypeName.methName, as context for the 234 // method-specific type params in the receiver. 235 g.curDecl = decl.Name.Value + "." + m.Name() 236 meth := g.obj(m) 237 methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type()) 238 methods[i].Nname = meth 239 g.curDecl = "" 240 } 241 ntyp.Methods().Set(methods) 242 } 243 244 out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name)) 245} 246 247func (g *irgen) varDecl(out *ir.Nodes, decl *syntax.VarDecl) { 248 pos := g.pos(decl) 249 // Set the position for any error messages we might print (e.g. too large types). 250 base.Pos = pos 251 names := make([]*ir.Name, len(decl.NameList)) 252 for i, name := range decl.NameList { 253 names[i], _ = g.def(name) 254 } 255 256 if decl.Pragma != nil { 257 pragma := decl.Pragma.(*pragmas) 258 varEmbed(g.makeXPos, names[0], decl, pragma, g.haveEmbed) 259 g.reportUnused(pragma) 260 } 261 262 haveEmbed := g.haveEmbed 263 do := func() { 264 defer func(b bool) { g.haveEmbed = b }(g.haveEmbed) 265 266 g.haveEmbed = haveEmbed 267 values := g.exprList(decl.Values) 268 269 var as2 *ir.AssignListStmt 270 if len(values) != 0 && len(names) != len(values) { 271 as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values) 272 } 273 274 for i, name := range names { 275 if ir.CurFunc != nil { 276 out.Append(ir.NewDecl(pos, ir.ODCL, name)) 277 } 278 if as2 != nil { 279 as2.Lhs[i] = name 280 name.Defn = as2 281 } else { 282 as := ir.NewAssignStmt(pos, name, nil) 283 if len(values) != 0 { 284 as.Y = values[i] 285 name.Defn = as 286 } else if ir.CurFunc == nil { 287 name.Defn = as 288 } 289 if !g.delayTransform() { 290 lhs := []ir.Node{as.X} 291 rhs := []ir.Node{} 292 if as.Y != nil { 293 rhs = []ir.Node{as.Y} 294 } 295 transformAssign(as, lhs, rhs) 296 as.X = lhs[0] 297 if as.Y != nil { 298 as.Y = rhs[0] 299 } 300 } 301 as.SetTypecheck(1) 302 out.Append(as) 303 } 304 } 305 if as2 != nil { 306 if !g.delayTransform() { 307 transformAssign(as2, as2.Lhs, as2.Rhs) 308 } 309 as2.SetTypecheck(1) 310 out.Append(as2) 311 } 312 } 313 314 // If we're within a function, we need to process the assignment 315 // part of the variable declaration right away. Otherwise, we leave 316 // it to be handled after all top-level declarations are processed. 317 if ir.CurFunc != nil { 318 do() 319 } else { 320 g.later(do) 321 } 322} 323 324// pragmaFlags returns any specified pragma flags included in allowed, 325// and reports errors about any other, unexpected pragmas. 326func (g *irgen) pragmaFlags(pragma syntax.Pragma, allowed ir.PragmaFlag) ir.PragmaFlag { 327 if pragma == nil { 328 return 0 329 } 330 p := pragma.(*pragmas) 331 present := p.Flag & allowed 332 p.Flag &^= allowed 333 g.reportUnused(p) 334 return present 335} 336 337// reportUnused reports errors about any unused pragmas. 338func (g *irgen) reportUnused(pragma *pragmas) { 339 for _, pos := range pragma.Pos { 340 if pos.Flag&pragma.Flag != 0 { 341 base.ErrorfAt(g.makeXPos(pos.Pos), "misplaced compiler directive") 342 } 343 } 344 if len(pragma.Embeds) > 0 { 345 for _, e := range pragma.Embeds { 346 base.ErrorfAt(g.makeXPos(e.Pos), "misplaced go:embed directive") 347 } 348 } 349} 350