Source file src/cmd/compile/internal/types/sym.go
1 // Copyright 2017 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 types 6 7 import ( 8 "cmd/compile/internal/base" 9 "cmd/internal/obj" 10 "cmd/internal/src" 11 "unicode" 12 "unicode/utf8" 13 ) 14 15 // Sym represents an object name in a segmented (pkg, name) namespace. 16 // Most commonly, this is a Go identifier naming an object declared within a package, 17 // but Syms are also used to name internal synthesized objects. 18 // 19 // As an exception, field and method names that are exported use the Sym 20 // associated with localpkg instead of the package that declared them. This 21 // allows using Sym pointer equality to test for Go identifier uniqueness when 22 // handling selector expressions. 23 // 24 // Ideally, Sym should be used for representing Go language constructs, 25 // while cmd/internal/obj.LSym is used for representing emitted artifacts. 26 // 27 // NOTE: In practice, things can be messier than the description above 28 // for various reasons (historical, convenience). 29 type Sym struct { 30 Linkname string // link name 31 32 Pkg *Pkg 33 Name string // object name 34 35 // Def, Block, and Lastlineno are saved and restored by Pushdcl/Popdcl. 36 37 // The unique ONAME, OTYPE, OPACK, or OLITERAL node that this symbol is 38 // bound to within the current scope. (Most parts of the compiler should 39 // prefer passing the Node directly, rather than relying on this field.) 40 Def Object 41 Block int32 // blocknumber to catch redeclaration 42 Lastlineno src.XPos // last declaration for diagnostic 43 44 flags bitset8 45 } 46 47 const ( 48 symOnExportList = 1 << iota // added to exportlist (no need to add again) 49 symUniq 50 symSiggen // type symbol has been generated 51 symAsm // on asmlist, for writing to -asmhdr 52 symFunc // function symbol 53 ) 54 55 func (sym *Sym) OnExportList() bool { return sym.flags&symOnExportList != 0 } 56 func (sym *Sym) Uniq() bool { return sym.flags&symUniq != 0 } 57 func (sym *Sym) Siggen() bool { return sym.flags&symSiggen != 0 } 58 func (sym *Sym) Asm() bool { return sym.flags&symAsm != 0 } 59 func (sym *Sym) Func() bool { return sym.flags&symFunc != 0 } 60 61 func (sym *Sym) SetOnExportList(b bool) { sym.flags.set(symOnExportList, b) } 62 func (sym *Sym) SetUniq(b bool) { sym.flags.set(symUniq, b) } 63 func (sym *Sym) SetSiggen(b bool) { sym.flags.set(symSiggen, b) } 64 func (sym *Sym) SetAsm(b bool) { sym.flags.set(symAsm, b) } 65 func (sym *Sym) SetFunc(b bool) { sym.flags.set(symFunc, b) } 66 67 func (sym *Sym) IsBlank() bool { 68 return sym != nil && sym.Name == "_" 69 } 70 71 // Deprecated: This method should not be used directly. Instead, use a 72 // higher-level abstraction that directly returns the linker symbol 73 // for a named object. For example, reflectdata.TypeLinksym(t) instead 74 // of reflectdata.TypeSym(t).Linksym(). 75 func (sym *Sym) Linksym() *obj.LSym { 76 abi := obj.ABI0 77 if sym.Func() { 78 abi = obj.ABIInternal 79 } 80 return sym.LinksymABI(abi) 81 } 82 83 // Deprecated: This method should not be used directly. Instead, use a 84 // higher-level abstraction that directly returns the linker symbol 85 // for a named object. For example, (*ir.Name).LinksymABI(abi) instead 86 // of (*ir.Name).Sym().LinksymABI(abi). 87 func (sym *Sym) LinksymABI(abi obj.ABI) *obj.LSym { 88 if sym == nil { 89 base.Fatalf("nil symbol") 90 } 91 if sym.Linkname != "" { 92 return base.Linkname(sym.Linkname, abi) 93 } 94 return base.PkgLinksym(sym.Pkg.Prefix, sym.Name, abi) 95 } 96 97 // Less reports whether symbol a is ordered before symbol b. 98 // 99 // Symbols are ordered exported before non-exported, then by name, and 100 // finally (for non-exported symbols) by package height and path. 101 // 102 // Ordering by package height is necessary to establish a consistent 103 // ordering for non-exported names with the same spelling but from 104 // different packages. We don't necessarily know the path for the 105 // package being compiled, but by definition it will have a height 106 // greater than any other packages seen within the compilation unit. 107 // For more background, see issue #24693. 108 func (a *Sym) Less(b *Sym) bool { 109 if a == b { 110 return false 111 } 112 113 // Nil before non-nil. 114 if a == nil { 115 return true 116 } 117 if b == nil { 118 return false 119 } 120 121 // Exported symbols before non-exported. 122 ea := IsExported(a.Name) 123 eb := IsExported(b.Name) 124 if ea != eb { 125 return ea 126 } 127 128 // Order by name and then (for non-exported names) by package 129 // height and path. 130 if a.Name != b.Name { 131 return a.Name < b.Name 132 } 133 if !ea { 134 if a.Pkg.Height != b.Pkg.Height { 135 return a.Pkg.Height < b.Pkg.Height 136 } 137 return a.Pkg.Path < b.Pkg.Path 138 } 139 return false 140 } 141 142 // IsExported reports whether name is an exported Go symbol (that is, 143 // whether it begins with an upper-case letter). 144 func IsExported(name string) bool { 145 if r := name[0]; r < utf8.RuneSelf { 146 return 'A' <= r && r <= 'Z' 147 } 148 r, _ := utf8.DecodeRuneInString(name) 149 return unicode.IsUpper(r) 150 } 151