Source file src/cmd/compile/internal/noder/decl.go

     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  	"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  
    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 && 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  	saveHaveEmbed := g.haveEmbed
   137  	saveCurDecl := g.curDecl
   138  	g.curDecl = ""
   139  	g.later(func() {
   140  		defer func(b bool, s string) {
   141  			// Revert haveEmbed and curDecl back to what they were before
   142  			// the "later" function.
   143  			g.haveEmbed = b
   144  			g.curDecl = s
   145  		}(g.haveEmbed, g.curDecl)
   146  
   147  		// Set haveEmbed and curDecl to what they were for this funcDecl.
   148  		g.haveEmbed = saveHaveEmbed
   149  		g.curDecl = saveCurDecl
   150  		if fn.Type().HasTParam() {
   151  			g.topFuncIsGeneric = true
   152  		}
   153  		g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
   154  		g.topFuncIsGeneric = false
   155  		if fn.Type().HasTParam() && fn.Body != nil {
   156  			// Set pointers to the dcls/body of a generic function/method in
   157  			// the Inl struct, so it is marked for export, is available for
   158  			// stenciling, and works with Inline_Flood().
   159  			fn.Inl = &ir.Inline{
   160  				Cost: 1,
   161  				Dcl:  fn.Dcl,
   162  				Body: fn.Body,
   163  			}
   164  		}
   165  
   166  		out.Append(fn)
   167  	})
   168  }
   169  
   170  func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
   171  	// Set the position for any error messages we might print (e.g. too large types).
   172  	base.Pos = g.pos(decl)
   173  	assert(ir.CurFunc != nil || g.curDecl == "")
   174  	// Set g.curDecl to the type name, as context for the type params declared
   175  	// during types2-to-types1 translation if this is a generic type.
   176  	saveCurDecl := g.curDecl
   177  	g.curDecl = decl.Name.Value
   178  	if decl.Alias {
   179  		name, _ := g.def(decl.Name)
   180  		g.pragmaFlags(decl.Pragma, 0)
   181  		assert(name.Alias()) // should be set by irgen.obj
   182  
   183  		out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
   184  		g.curDecl = ""
   185  		return
   186  	}
   187  
   188  	// Prevent size calculations until we set the underlying type.
   189  	types.DeferCheckSize()
   190  
   191  	name, obj := g.def(decl.Name)
   192  	ntyp, otyp := name.Type(), obj.Type()
   193  	if ir.CurFunc != nil {
   194  		ntyp.SetVargen()
   195  	}
   196  
   197  	pragmas := g.pragmaFlags(decl.Pragma, typePragmas)
   198  	name.SetPragma(pragmas) // TODO(mdempsky): Is this still needed?
   199  
   200  	if pragmas&ir.NotInHeap != 0 {
   201  		ntyp.SetNotInHeap(true)
   202  	}
   203  
   204  	// We need to use g.typeExpr(decl.Type) here to ensure that for
   205  	// chained, defined-type declarations like:
   206  	//
   207  	//	type T U
   208  	//
   209  	//	//go:notinheap
   210  	//	type U struct { … }
   211  	//
   212  	// we mark both T and U as NotInHeap. If we instead used just
   213  	// g.typ(otyp.Underlying()), then we'd instead set T's underlying
   214  	// type directly to the struct type (which is not marked NotInHeap)
   215  	// and fail to mark T as NotInHeap.
   216  	//
   217  	// Also, we rely here on Type.SetUnderlying allowing passing a
   218  	// defined type and handling forward references like from T to U
   219  	// above. Contrast with go/types's Named.SetUnderlying, which
   220  	// disallows this.
   221  	//
   222  	// [mdempsky: Subtleties like these are why I always vehemently
   223  	// object to new type pragmas.]
   224  	ntyp.SetUnderlying(g.typeExpr(decl.Type))
   225  
   226  	tparams := otyp.(*types2.Named).TypeParams()
   227  	if n := tparams.Len(); n > 0 {
   228  		rparams := make([]*types.Type, n)
   229  		for i := range rparams {
   230  			rparams[i] = g.typ(tparams.At(i))
   231  		}
   232  		// This will set hasTParam flag if any rparams are not concrete types.
   233  		ntyp.SetRParams(rparams)
   234  	}
   235  	types.ResumeCheckSize()
   236  
   237  	g.curDecl = saveCurDecl
   238  	if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 {
   239  		methods := make([]*types.Field, otyp.NumMethods())
   240  		for i := range methods {
   241  			m := otyp.Method(i)
   242  			// Set g.curDecl to recvTypeName.methName, as context for the
   243  			// method-specific type params in the receiver.
   244  			g.curDecl = decl.Name.Value + "." + m.Name()
   245  			meth := g.obj(m)
   246  			methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
   247  			methods[i].Nname = meth
   248  			g.curDecl = ""
   249  		}
   250  		ntyp.Methods().Set(methods)
   251  	}
   252  
   253  	out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
   254  }
   255  
   256  func (g *irgen) varDecl(out *ir.Nodes, decl *syntax.VarDecl) {
   257  	pos := g.pos(decl)
   258  	// Set the position for any error messages we might print (e.g. too large types).
   259  	base.Pos = pos
   260  	names := make([]*ir.Name, len(decl.NameList))
   261  	for i, name := range decl.NameList {
   262  		names[i], _ = g.def(name)
   263  	}
   264  
   265  	if decl.Pragma != nil {
   266  		pragma := decl.Pragma.(*pragmas)
   267  		varEmbed(g.makeXPos, names[0], decl, pragma, g.haveEmbed)
   268  		g.reportUnused(pragma)
   269  	}
   270  
   271  	haveEmbed := g.haveEmbed
   272  	do := func() {
   273  		defer func(b bool) { g.haveEmbed = b }(g.haveEmbed)
   274  
   275  		g.haveEmbed = haveEmbed
   276  		values := g.exprList(decl.Values)
   277  
   278  		var as2 *ir.AssignListStmt
   279  		if len(values) != 0 && len(names) != len(values) {
   280  			as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values)
   281  		}
   282  
   283  		for i, name := range names {
   284  			if ir.CurFunc != nil {
   285  				out.Append(ir.NewDecl(pos, ir.ODCL, name))
   286  			}
   287  			if as2 != nil {
   288  				as2.Lhs[i] = name
   289  				name.Defn = as2
   290  			} else {
   291  				as := ir.NewAssignStmt(pos, name, nil)
   292  				if len(values) != 0 {
   293  					as.Y = values[i]
   294  					name.Defn = as
   295  				} else if ir.CurFunc == nil {
   296  					name.Defn = as
   297  				}
   298  				if !g.delayTransform() {
   299  					lhs := []ir.Node{as.X}
   300  					rhs := []ir.Node{}
   301  					if as.Y != nil {
   302  						rhs = []ir.Node{as.Y}
   303  					}
   304  					transformAssign(as, lhs, rhs)
   305  					as.X = lhs[0]
   306  					if as.Y != nil {
   307  						as.Y = rhs[0]
   308  					}
   309  				}
   310  				as.SetTypecheck(1)
   311  				out.Append(as)
   312  			}
   313  		}
   314  		if as2 != nil {
   315  			if !g.delayTransform() {
   316  				transformAssign(as2, as2.Lhs, as2.Rhs)
   317  			}
   318  			as2.SetTypecheck(1)
   319  			out.Append(as2)
   320  		}
   321  	}
   322  
   323  	// If we're within a function, we need to process the assignment
   324  	// part of the variable declaration right away. Otherwise, we leave
   325  	// it to be handled after all top-level declarations are processed.
   326  	if ir.CurFunc != nil {
   327  		do()
   328  	} else {
   329  		g.later(do)
   330  	}
   331  }
   332  
   333  // pragmaFlags returns any specified pragma flags included in allowed,
   334  // and reports errors about any other, unexpected pragmas.
   335  func (g *irgen) pragmaFlags(pragma syntax.Pragma, allowed ir.PragmaFlag) ir.PragmaFlag {
   336  	if pragma == nil {
   337  		return 0
   338  	}
   339  	p := pragma.(*pragmas)
   340  	present := p.Flag & allowed
   341  	p.Flag &^= allowed
   342  	g.reportUnused(p)
   343  	return present
   344  }
   345  
   346  // reportUnused reports errors about any unused pragmas.
   347  func (g *irgen) reportUnused(pragma *pragmas) {
   348  	for _, pos := range pragma.Pos {
   349  		if pos.Flag&pragma.Flag != 0 {
   350  			base.ErrorfAt(g.makeXPos(pos.Pos), "misplaced compiler directive")
   351  		}
   352  	}
   353  	if len(pragma.Embeds) > 0 {
   354  		for _, e := range pragma.Embeds {
   355  			base.ErrorfAt(g.makeXPos(e.Pos), "misplaced go:embed directive")
   356  		}
   357  	}
   358  }
   359  

View as plain text