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 "strings" 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 // The unique ONAME, OTYPE, OPACK, or OLITERAL node that this symbol is 36 // bound to within the current scope. (Most parts of the compiler should 37 // prefer passing the Node directly, rather than relying on this field.) 38 // 39 // Deprecated: New code should avoid depending on Sym.Def. Add 40 // mdempsky@ as a reviewer for any CLs involving Sym.Def. 41 Def Object 42 43 flags bitset8 44 } 45 46 const ( 47 symOnExportList = 1 << iota // added to exportlist (no need to add again) 48 symUniq 49 symSiggen // type symbol has been generated 50 symAsm // on asmlist, for writing to -asmhdr 51 symFunc // function symbol 52 ) 53 54 func (sym *Sym) OnExportList() bool { return sym.flags&symOnExportList != 0 } 55 func (sym *Sym) Uniq() bool { return sym.flags&symUniq != 0 } 56 func (sym *Sym) Siggen() bool { return sym.flags&symSiggen != 0 } 57 func (sym *Sym) Asm() bool { return sym.flags&symAsm != 0 } 58 func (sym *Sym) Func() bool { return sym.flags&symFunc != 0 } 59 60 func (sym *Sym) SetOnExportList(b bool) { sym.flags.set(symOnExportList, b) } 61 func (sym *Sym) SetUniq(b bool) { sym.flags.set(symUniq, b) } 62 func (sym *Sym) SetSiggen(b bool) { sym.flags.set(symSiggen, b) } 63 func (sym *Sym) SetAsm(b bool) { sym.flags.set(symAsm, b) } 64 func (sym *Sym) SetFunc(b bool) { sym.flags.set(symFunc, b) } 65 66 func (sym *Sym) IsBlank() bool { 67 return sym != nil && sym.Name == "_" 68 } 69 70 // Deprecated: This method should not be used directly. Instead, use a 71 // higher-level abstraction that directly returns the linker symbol 72 // for a named object. For example, reflectdata.TypeLinksym(t) instead 73 // of reflectdata.TypeSym(t).Linksym(). 74 func (sym *Sym) Linksym() *obj.LSym { 75 abi := obj.ABI0 76 if sym.Func() { 77 abi = obj.ABIInternal 78 } 79 return sym.LinksymABI(abi) 80 } 81 82 // Deprecated: This method should not be used directly. Instead, use a 83 // higher-level abstraction that directly returns the linker symbol 84 // for a named object. For example, (*ir.Name).LinksymABI(abi) instead 85 // of (*ir.Name).Sym().LinksymABI(abi). 86 func (sym *Sym) LinksymABI(abi obj.ABI) *obj.LSym { 87 if sym == nil { 88 base.Fatalf("nil symbol") 89 } 90 if sym.Linkname != "" { 91 return base.Linkname(sym.Linkname, abi) 92 } 93 return base.PkgLinksym(sym.Pkg.Prefix, sym.Name, abi) 94 } 95 96 // CompareSyms return the ordering of a and b, as for [cmp.Compare]. 97 // 98 // Symbols are ordered exported before non-exported, then by name, and 99 // finally (for non-exported symbols) by package path. 100 func CompareSyms(a, b *Sym) int { 101 if a == b { 102 return 0 103 } 104 105 // Nil before non-nil. 106 if a == nil { 107 return -1 108 } 109 if b == nil { 110 return +1 111 } 112 113 // Exported symbols before non-exported. 114 ea := IsExported(a.Name) 115 eb := IsExported(b.Name) 116 if ea != eb { 117 if ea { 118 return -1 119 } else { 120 return +1 121 } 122 } 123 124 // Order by name and then (for non-exported names) by package 125 // height and path. 126 if r := strings.Compare(a.Name, b.Name); r != 0 { 127 return r 128 } 129 if !ea { 130 return strings.Compare(a.Pkg.Path, b.Pkg.Path) 131 } 132 return 0 133 } 134 135 // IsExported reports whether name is an exported Go symbol (that is, 136 // whether it begins with an upper-case letter). 137 func IsExported(name string) bool { 138 if r := name[0]; r < utf8.RuneSelf { 139 return 'A' <= r && r <= 'Z' 140 } 141 r, _ := utf8.DecodeRuneInString(name) 142 return unicode.IsUpper(r) 143 } 144