Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/compile/internal/noder

     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(decls []syntax.Decl) []ir.Node {
    22  	var res ir.Nodes
    23  	for _, decl := range decls {
    24  		switch decl := decl.(type) {
    25  		case *syntax.ConstDecl:
    26  			g.constDecl(&res, decl)
    27  		case *syntax.FuncDecl:
    28  			g.funcDecl(&res, decl)
    29  		case *syntax.TypeDecl:
    30  			if ir.CurFunc == nil {
    31  				continue // already handled in irgen.generate
    32  			}
    33  			g.typeDecl(&res, decl)
    34  		case *syntax.VarDecl:
    35  			g.varDecl(&res, decl)
    36  		default:
    37  			g.unhandled("declaration", decl)
    38  		}
    39  	}
    40  	return res
    41  }
    42  
    43  func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) {
    44  	// TODO(mdempsky): Merge with gcimports so we don't have to import
    45  	// packages twice.
    46  
    47  	g.pragmaFlags(decl.Pragma, 0)
    48  
    49  	ipkg := importfile(decl)
    50  	if ipkg == ir.Pkgs.Unsafe {
    51  		p.importedUnsafe = true
    52  	}
    53  	if ipkg.Path == "embed" {
    54  		p.importedEmbed = true
    55  	}
    56  }
    57  
    58  func (g *irgen) constDecl(out *ir.Nodes, decl *syntax.ConstDecl) {
    59  	g.pragmaFlags(decl.Pragma, 0)
    60  
    61  	for _, name := range decl.NameList {
    62  		name, obj := g.def(name)
    63  
    64  		// For untyped numeric constants, make sure the value
    65  		// representation matches what the rest of the
    66  		// compiler (really just iexport) expects.
    67  		// TODO(mdempsky): Revisit after #43891 is resolved.
    68  		val := obj.(*types2.Const).Val()
    69  		switch name.Type() {
    70  		case types.UntypedInt, types.UntypedRune:
    71  			val = constant.ToInt(val)
    72  		case types.UntypedFloat:
    73  			val = constant.ToFloat(val)
    74  		case types.UntypedComplex:
    75  			val = constant.ToComplex(val)
    76  		}
    77  		name.SetVal(val)
    78  
    79  		out.Append(ir.NewDecl(g.pos(decl), ir.ODCLCONST, name))
    80  	}
    81  }
    82  
    83  func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
    84  	fn := ir.NewFunc(g.pos(decl))
    85  	fn.Nname, _ = g.def(decl.Name)
    86  	fn.Nname.Func = fn
    87  	fn.Nname.Defn = fn
    88  
    89  	fn.Pragma = g.pragmaFlags(decl.Pragma, funcPragmas)
    90  	if fn.Pragma&ir.Systemstack != 0 && fn.Pragma&ir.Nosplit != 0 {
    91  		base.ErrorfAt(fn.Pos(), "go:nosplit and go:systemstack cannot be combined")
    92  	}
    93  
    94  	if decl.Name.Value == "init" && decl.Recv == nil {
    95  		g.target.Inits = append(g.target.Inits, fn)
    96  	}
    97  
    98  	g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
    99  
   100  	out.Append(fn)
   101  }
   102  
   103  func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
   104  	if decl.Alias {
   105  		name, _ := g.def(decl.Name)
   106  		g.pragmaFlags(decl.Pragma, 0)
   107  
   108  		// TODO(mdempsky): This matches how typecheckdef marks aliases for
   109  		// export, but this won't generalize to exporting function-scoped
   110  		// type aliases. We should maybe just use n.Alias() instead.
   111  		if ir.CurFunc == nil {
   112  			name.Sym().Def = ir.TypeNode(name.Type())
   113  		}
   114  
   115  		out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
   116  		return
   117  	}
   118  
   119  	// Prevent size calculations until we set the underlying type.
   120  	types.DeferCheckSize()
   121  
   122  	name, obj := g.def(decl.Name)
   123  	ntyp, otyp := name.Type(), obj.Type()
   124  	if ir.CurFunc != nil {
   125  		typecheck.TypeGen++
   126  		ntyp.Vargen = typecheck.TypeGen
   127  	}
   128  
   129  	pragmas := g.pragmaFlags(decl.Pragma, typePragmas)
   130  	name.SetPragma(pragmas) // TODO(mdempsky): Is this still needed?
   131  
   132  	if pragmas&ir.NotInHeap != 0 {
   133  		ntyp.SetNotInHeap(true)
   134  	}
   135  
   136  	// We need to use g.typeExpr(decl.Type) here to ensure that for
   137  	// chained, defined-type declarations like:
   138  	//
   139  	//	type T U
   140  	//
   141  	//	//go:notinheap
   142  	//	type U struct { … }
   143  	//
   144  	// we mark both T and U as NotInHeap. If we instead used just
   145  	// g.typ(otyp.Underlying()), then we'd instead set T's underlying
   146  	// type directly to the struct type (which is not marked NotInHeap)
   147  	// and fail to mark T as NotInHeap.
   148  	//
   149  	// Also, we rely here on Type.SetUnderlying allowing passing a
   150  	// defined type and handling forward references like from T to U
   151  	// above. Contrast with go/types's Named.SetUnderlying, which
   152  	// disallows this.
   153  	//
   154  	// [mdempsky: Subtleties like these are why I always vehemently
   155  	// object to new type pragmas.]
   156  	ntyp.SetUnderlying(g.typeExpr(decl.Type))
   157  	if len(decl.TParamList) > 0 {
   158  		// Set HasTParam if there are any tparams, even if no tparams are
   159  		// used in the type itself (e.g., if it is an empty struct, or no
   160  		// fields in the struct use the tparam).
   161  		ntyp.SetHasTParam(true)
   162  	}
   163  	types.ResumeCheckSize()
   164  
   165  	if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 {
   166  		methods := make([]*types.Field, otyp.NumMethods())
   167  		for i := range methods {
   168  			m := otyp.Method(i)
   169  			meth := g.obj(m)
   170  			methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
   171  			methods[i].Nname = meth
   172  		}
   173  		ntyp.Methods().Set(methods)
   174  	}
   175  
   176  	out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
   177  }
   178  
   179  func (g *irgen) varDecl(out *ir.Nodes, decl *syntax.VarDecl) {
   180  	pos := g.pos(decl)
   181  	names := make([]*ir.Name, len(decl.NameList))
   182  	for i, name := range decl.NameList {
   183  		names[i], _ = g.def(name)
   184  	}
   185  	values := g.exprList(decl.Values)
   186  
   187  	if decl.Pragma != nil {
   188  		pragma := decl.Pragma.(*pragmas)
   189  		// TODO(mdempsky): Plumb noder.importedEmbed through to here.
   190  		varEmbed(g.makeXPos, names[0], decl, pragma, true)
   191  		g.reportUnused(pragma)
   192  	}
   193  
   194  	var as2 *ir.AssignListStmt
   195  	if len(values) != 0 && len(names) != len(values) {
   196  		as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values)
   197  	}
   198  
   199  	for i, name := range names {
   200  		if ir.CurFunc != nil {
   201  			out.Append(ir.NewDecl(pos, ir.ODCL, name))
   202  		}
   203  		if as2 != nil {
   204  			as2.Lhs[i] = name
   205  			name.Defn = as2
   206  		} else {
   207  			as := ir.NewAssignStmt(pos, name, nil)
   208  			if len(values) != 0 {
   209  				as.Y = values[i]
   210  				name.Defn = as
   211  			} else if ir.CurFunc == nil {
   212  				name.Defn = as
   213  			}
   214  			lhs := []ir.Node{as.X}
   215  			rhs := []ir.Node{}
   216  			if as.Y != nil {
   217  				rhs = []ir.Node{as.Y}
   218  			}
   219  			transformAssign(as, lhs, rhs)
   220  			as.X = lhs[0]
   221  			if as.Y != nil {
   222  				as.Y = rhs[0]
   223  			}
   224  			as.SetTypecheck(1)
   225  			out.Append(as)
   226  		}
   227  	}
   228  	if as2 != nil {
   229  		transformAssign(as2, as2.Lhs, as2.Rhs)
   230  		as2.SetTypecheck(1)
   231  		out.Append(as2)
   232  	}
   233  }
   234  
   235  // pragmaFlags returns any specified pragma flags included in allowed,
   236  // and reports errors about any other, unexpected pragmas.
   237  func (g *irgen) pragmaFlags(pragma syntax.Pragma, allowed ir.PragmaFlag) ir.PragmaFlag {
   238  	if pragma == nil {
   239  		return 0
   240  	}
   241  	p := pragma.(*pragmas)
   242  	present := p.Flag & allowed
   243  	p.Flag &^= allowed
   244  	g.reportUnused(p)
   245  	return present
   246  }
   247  
   248  // reportUnused reports errors about any unused pragmas.
   249  func (g *irgen) reportUnused(pragma *pragmas) {
   250  	for _, pos := range pragma.Pos {
   251  		if pos.Flag&pragma.Flag != 0 {
   252  			base.ErrorfAt(g.makeXPos(pos.Pos), "misplaced compiler directive")
   253  		}
   254  	}
   255  	if len(pragma.Embeds) > 0 {
   256  		for _, e := range pragma.Embeds {
   257  			base.ErrorfAt(g.makeXPos(e.Pos), "misplaced go:embed directive")
   258  		}
   259  	}
   260  }
   261  

View as plain text