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  }