Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/types/sym.go

Documentation: cmd/compile/internal/types

     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  	// Exported symbols before non-exported.
   114  	ea := IsExported(a.Name)
   115  	eb := IsExported(b.Name)
   116  	if ea != eb {
   117  		return ea
   118  	}
   119  
   120  	// Order by name and then (for non-exported names) by package
   121  	// height and path.
   122  	if a.Name != b.Name {
   123  		return a.Name < b.Name
   124  	}
   125  	if !ea {
   126  		if a.Pkg.Height != b.Pkg.Height {
   127  			return a.Pkg.Height < b.Pkg.Height
   128  		}
   129  		return a.Pkg.Path < b.Pkg.Path
   130  	}
   131  	return false
   132  }
   133  
   134  // IsExported reports whether name is an exported Go symbol (that is,
   135  // whether it begins with an upper-case letter).
   136  func IsExported(name string) bool {
   137  	if r := name[0]; r < utf8.RuneSelf {
   138  		return 'A' <= r && r <= 'Z'
   139  	}
   140  	r, _ := utf8.DecodeRuneInString(name)
   141  	return unicode.IsUpper(r)
   142  }
   143  

View as plain text