github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/noder/decl.go (about) 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 5 package noder 6 7 import ( 8 "github.com/bir3/gocompiler/src/go/constant" 9 10 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 11 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 12 "github.com/bir3/gocompiler/src/cmd/compile/internal/syntax" 13 "github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck" 14 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 15 "github.com/bir3/gocompiler/src/cmd/compile/internal/types2" 16 ) 17 18 // TODO(mdempsky): Skip blank declarations? Probably only safe 19 // for declarations without pragmas. 20 21 func (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 41 func (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. 56 func 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 63 func (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 88 func (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 orig := typ.OrigType(); orig != 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 = orig 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 { 129 if fn.Pragma&ir.Noescape != 0 { 130 base.ErrorfAt(fn.Pos(), "can only use //go:noescape with external func implementations") 131 } 132 if (fn.Pragma&ir.UintptrKeepAlive != 0 && fn.Pragma&ir.UintptrEscapes == 0) && fn.Pragma&ir.Nosplit == 0 { 133 // Stack growth can't handle uintptr arguments that may 134 // be pointers (as we don't know which are pointers 135 // when creating the stack map). Thus uintptrkeepalive 136 // functions (and all transitive callees) must be 137 // nosplit. 138 // 139 // N.B. uintptrescapes implies uintptrkeepalive but it 140 // is OK since the arguments must escape to the heap. 141 // 142 // TODO(prattmic): Add recursive nosplit check of callees. 143 // TODO(prattmic): Functions with no body (i.e., 144 // assembly) must also be nosplit, but we can't check 145 // that here. 146 base.ErrorfAt(fn.Pos(), "go:uintptrkeepalive requires go:nosplit") 147 } 148 } 149 150 if decl.Name.Value == "init" && decl.Recv == nil { 151 g.target.Inits = append(g.target.Inits, fn) 152 } 153 154 saveHaveEmbed := g.haveEmbed 155 saveCurDecl := g.curDecl 156 g.curDecl = "" 157 g.later(func() { 158 defer func(b bool, s string) { 159 // Revert haveEmbed and curDecl back to what they were before 160 // the "later" function. 161 g.haveEmbed = b 162 g.curDecl = s 163 }(g.haveEmbed, g.curDecl) 164 165 // Set haveEmbed and curDecl to what they were for this funcDecl. 166 g.haveEmbed = saveHaveEmbed 167 g.curDecl = saveCurDecl 168 if fn.Type().HasTParam() { 169 g.topFuncIsGeneric = true 170 } 171 g.funcBody(fn, decl.Recv, decl.Type, decl.Body) 172 g.topFuncIsGeneric = false 173 if fn.Type().HasTParam() && fn.Body != nil { 174 // Set pointers to the dcls/body of a generic function/method in 175 // the Inl struct, so it is marked for export, is available for 176 // stenciling, and works with Inline_Flood(). 177 fn.Inl = &ir.Inline{ 178 Cost: 1, 179 Dcl: fn.Dcl, 180 Body: fn.Body, 181 } 182 } 183 184 out.Append(fn) 185 }) 186 } 187 188 func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) { 189 // Set the position for any error messages we might print (e.g. too large types). 190 base.Pos = g.pos(decl) 191 assert(ir.CurFunc != nil || g.curDecl == "") 192 // Set g.curDecl to the type name, as context for the type params declared 193 // during types2-to-types1 translation if this is a generic type. 194 saveCurDecl := g.curDecl 195 g.curDecl = decl.Name.Value 196 if decl.Alias { 197 name, _ := g.def(decl.Name) 198 g.pragmaFlags(decl.Pragma, 0) 199 assert(name.Alias()) // should be set by irgen.obj 200 201 out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name)) 202 g.curDecl = "" 203 return 204 } 205 206 // Prevent size calculations until we set the underlying type. 207 types.DeferCheckSize() 208 209 name, obj := g.def(decl.Name) 210 ntyp, otyp := name.Type(), obj.Type() 211 if ir.CurFunc != nil { 212 ntyp.SetVargen() 213 } 214 215 pragmas := g.pragmaFlags(decl.Pragma, 0) 216 name.SetPragma(pragmas) // TODO(mdempsky): Is this still needed? 217 218 ntyp.SetUnderlying(g.typeExpr(decl.Type)) 219 220 tparams := otyp.(*types2.Named).TypeParams() 221 if n := tparams.Len(); n > 0 { 222 rparams := make([]*types.Type, n) 223 for i := range rparams { 224 rparams[i] = g.typ(tparams.At(i)) 225 } 226 // This will set hasTParam flag if any rparams are not concrete types. 227 ntyp.SetRParams(rparams) 228 } 229 types.ResumeCheckSize() 230 231 g.curDecl = saveCurDecl 232 if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 { 233 methods := make([]*types.Field, otyp.NumMethods()) 234 for i := range methods { 235 m := otyp.Method(i) 236 // Set g.curDecl to recvTypeName.methName, as context for the 237 // method-specific type params in the receiver. 238 g.curDecl = decl.Name.Value + "." + m.Name() 239 meth := g.obj(m) 240 methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type()) 241 methods[i].Nname = meth 242 g.curDecl = "" 243 } 244 ntyp.Methods().Set(methods) 245 } 246 247 out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name)) 248 } 249 250 func (g *irgen) varDecl(out *ir.Nodes, decl *syntax.VarDecl) { 251 pos := g.pos(decl) 252 // Set the position for any error messages we might print (e.g. too large types). 253 base.Pos = pos 254 names := make([]*ir.Name, len(decl.NameList)) 255 for i, name := range decl.NameList { 256 names[i], _ = g.def(name) 257 } 258 259 if decl.Pragma != nil { 260 pragma := decl.Pragma.(*pragmas) 261 varEmbed(g.makeXPos, names[0], decl, pragma, g.haveEmbed) 262 g.reportUnused(pragma) 263 } 264 265 haveEmbed := g.haveEmbed 266 do := func() { 267 defer func(b bool) { g.haveEmbed = b }(g.haveEmbed) 268 269 g.haveEmbed = haveEmbed 270 values := g.exprList(decl.Values) 271 272 var as2 *ir.AssignListStmt 273 if len(values) != 0 && len(names) != len(values) { 274 as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values) 275 } 276 277 for i, name := range names { 278 if ir.CurFunc != nil { 279 out.Append(ir.NewDecl(pos, ir.ODCL, name)) 280 } 281 if as2 != nil { 282 as2.Lhs[i] = name 283 name.Defn = as2 284 } else { 285 as := ir.NewAssignStmt(pos, name, nil) 286 if len(values) != 0 { 287 as.Y = values[i] 288 name.Defn = as 289 } else if ir.CurFunc == nil { 290 name.Defn = as 291 } 292 if !g.delayTransform() { 293 lhs := []ir.Node{as.X} 294 rhs := []ir.Node{} 295 if as.Y != nil { 296 rhs = []ir.Node{as.Y} 297 } 298 transformAssign(as, lhs, rhs) 299 as.X = lhs[0] 300 if as.Y != nil { 301 as.Y = rhs[0] 302 } 303 } 304 as.SetTypecheck(1) 305 out.Append(as) 306 } 307 } 308 if as2 != nil { 309 if !g.delayTransform() { 310 transformAssign(as2, as2.Lhs, as2.Rhs) 311 } 312 as2.SetTypecheck(1) 313 out.Append(as2) 314 } 315 } 316 317 // If we're within a function, we need to process the assignment 318 // part of the variable declaration right away. Otherwise, we leave 319 // it to be handled after all top-level declarations are processed. 320 if ir.CurFunc != nil { 321 do() 322 } else { 323 g.later(do) 324 } 325 } 326 327 // pragmaFlags returns any specified pragma flags included in allowed, 328 // and reports errors about any other, unexpected pragmas. 329 func (g *irgen) pragmaFlags(pragma syntax.Pragma, allowed ir.PragmaFlag) ir.PragmaFlag { 330 if pragma == nil { 331 return 0 332 } 333 p := pragma.(*pragmas) 334 present := p.Flag & allowed 335 p.Flag &^= allowed 336 g.reportUnused(p) 337 return present 338 } 339 340 // reportUnused reports errors about any unused pragmas. 341 func (g *irgen) reportUnused(pragma *pragmas) { 342 for _, pos := range pragma.Pos { 343 if pos.Flag&pragma.Flag != 0 { 344 base.ErrorfAt(g.makeXPos(pos.Pos), "misplaced compiler directive") 345 } 346 } 347 if len(pragma.Embeds) > 0 { 348 for _, e := range pragma.Embeds { 349 base.ErrorfAt(g.makeXPos(e.Pos), "misplaced go:embed directive") 350 } 351 } 352 }