aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/ianlancetaylor
diff options
context:
space:
mode:
authorTaras Madan <tarasmadan@google.com>2022-09-05 14:27:54 +0200
committerGitHub <noreply@github.com>2022-09-05 12:27:54 +0000
commitb2f2446b46bf02821d90ebedadae2bf7ae0e880e (patch)
tree923cf42842918d6bebca1d6bbdc08abed54d274d /vendor/github.com/ianlancetaylor
parente6654faff4bcca4be92e9a8596fd4b77f747c39e (diff)
go.mod, vendor: update (#3358)
* go.mod, vendor: remove unnecessary dependencies Commands: 1. go mod tidy 2. go mod vendor * go.mod, vendor: update cloud.google.com/go Commands: 1. go get -u cloud.google.com/go 2. go mod tidy 3. go mod vendor * go.mod, vendor: update cloud.google.com/* Commands: 1. go get -u cloud.google.com/storage cloud.google.com/logging 2. go mod tidy 3. go mod vendor * go.mod, .golangci.yml, vendor: update *lint* Commands: 1. go get -u golang.org/x/tools github.com/golangci/golangci-lint@v1.47.0 2. go mod tidy 3. go mod vendor 4. edit .golangci.yml to suppress new errors (resolved in the same PR later) * all: fix lint errors hash.go: copy() recommended by gosimple parse.go: ent is never nil verifier.go: signal.Notify() with unbuffered channel is bad. Have no idea why. * .golangci.yml: adjust godot rules check-all is deprecated, but still work if you're hesitating too - I'll remove this commit
Diffstat (limited to 'vendor/github.com/ianlancetaylor')
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/README.md2
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/ast.go982
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/demangle.go574
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/go.mod3
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/rust.go1069
5 files changed, 2482 insertions, 148 deletions
diff --git a/vendor/github.com/ianlancetaylor/demangle/README.md b/vendor/github.com/ianlancetaylor/demangle/README.md
index ef3f94a63..2c01cae08 100644
--- a/vendor/github.com/ianlancetaylor/demangle/README.md
+++ b/vendor/github.com/ianlancetaylor/demangle/README.md
@@ -1,3 +1,3 @@
# github.com/ianlancetaylor/demangle
-A Go package that can be used to demangle C++ symbol names.
+A Go package that can be used to demangle C++ and Rust symbol names.
diff --git a/vendor/github.com/ianlancetaylor/demangle/ast.go b/vendor/github.com/ianlancetaylor/demangle/ast.go
index ccbe5b355..7b9178f1b 100644
--- a/vendor/github.com/ianlancetaylor/demangle/ast.go
+++ b/vendor/github.com/ianlancetaylor/demangle/ast.go
@@ -11,6 +11,7 @@ import (
// AST is an abstract syntax tree representing a C++ declaration.
// This is sufficient for the demangler but is by no means a general C++ AST.
+// This abstract syntax tree is only used for C++ symbols, not Rust symbols.
type AST interface {
// Internal method to convert to demangled string.
print(*printState)
@@ -37,21 +38,25 @@ type AST interface {
// ASTToString returns the demangled name of the AST.
func ASTToString(a AST, options ...Option) string {
tparams := true
+ llvmStyle := false
for _, o := range options {
switch o {
case NoTemplateParams:
tparams = false
+ case LLVMStyle:
+ llvmStyle = true
}
}
- ps := printState{tparams: tparams}
+ ps := printState{tparams: tparams, llvmStyle: llvmStyle}
a.print(&ps)
return ps.buf.String()
}
// The printState type holds information needed to print an AST.
type printState struct {
- tparams bool // whether to print template parameters
+ tparams bool // whether to print template parameters
+ llvmStyle bool
buf strings.Builder
last byte // Last byte written to buffer.
@@ -408,7 +413,11 @@ type LambdaAuto struct {
func (la *LambdaAuto) print(ps *printState) {
// We print the index plus 1 because that is what the standard
// demangler does.
- fmt.Fprintf(&ps.buf, "auto:%d", la.Index+1)
+ if ps.llvmStyle {
+ ps.writeString("auto")
+ } else {
+ fmt.Fprintf(&ps.buf, "auto:%d", la.Index+1)
+ }
}
func (la *LambdaAuto) Traverse(fn func(AST) bool) {
@@ -504,6 +513,9 @@ func (q *Qualifier) print(ps *printState) {
ps.writeByte('(')
first := true
for _, e := range q.Exprs {
+ if el, ok := e.(*ExprList); ok && len(el.Exprs) == 0 {
+ continue
+ }
if !first {
ps.writeString(", ")
}
@@ -715,7 +727,11 @@ type BuiltinType struct {
}
func (bt *BuiltinType) print(ps *printState) {
- ps.writeString(bt.Name)
+ name := bt.Name
+ if ps.llvmStyle && name == "decltype(nullptr)" {
+ name = "std::nullptr_t"
+ }
+ ps.writeString(name)
}
func (bt *BuiltinType) Traverse(fn func(AST) bool) {
@@ -970,10 +986,15 @@ type VendorQualifier struct {
}
func (vq *VendorQualifier) print(ps *printState) {
- ps.inner = append(ps.inner, vq)
- ps.print(vq.Type)
- if len(ps.inner) > 0 {
- ps.printOneInner(nil)
+ if ps.llvmStyle {
+ ps.print(vq.Type)
+ vq.printInner(ps)
+ } else {
+ ps.inner = append(ps.inner, vq)
+ ps.print(vq.Type)
+ if len(ps.inner) > 0 {
+ ps.printOneInner(nil)
+ }
}
}
@@ -1110,19 +1131,27 @@ func (at *ArrayType) goString(indent int, field string) string {
at.Element.goString(indent+2, "Element: "))
}
-// FunctionType is a function type. The Return field may be nil for
-// cases where the return type is not part of the mangled name.
+// FunctionType is a function type.
type FunctionType struct {
Return AST
Args []AST
+
+ // The forLocalName field reports whether this FunctionType
+ // was created for a local name. With the default GNU demangling
+ // output we don't print the return type in that case.
+ ForLocalName bool
}
func (ft *FunctionType) print(ps *printState) {
- if ft.Return != nil {
+ retType := ft.Return
+ if ft.ForLocalName && !ps.llvmStyle {
+ retType = nil
+ }
+ if retType != nil {
// Pass the return type as an inner type in order to
// print the arguments in the right location.
ps.inner = append(ps.inner, ft)
- ps.print(ft.Return)
+ ps.print(retType)
if len(ps.inner) == 0 {
// Everything was printed.
return
@@ -1227,7 +1256,11 @@ func (ft *FunctionType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if !changed {
return fn(ft)
}
- ft = &FunctionType{Return: ret, Args: args}
+ ft = &FunctionType{
+ Return: ret,
+ Args: args,
+ ForLocalName: ft.ForLocalName,
+ }
if r := fn(ft); r != nil {
return r
}
@@ -1239,6 +1272,10 @@ func (ft *FunctionType) GoString() string {
}
func (ft *FunctionType) goString(indent int, field string) string {
+ var forLocalName string
+ if ft.ForLocalName {
+ forLocalName = " ForLocalName: true"
+ }
var r string
if ft.Return == nil {
r = fmt.Sprintf("%*sReturn: nil", indent+2, "")
@@ -1255,7 +1292,8 @@ func (ft *FunctionType) goString(indent int, field string) string {
args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
}
}
- return fmt.Sprintf("%*s%sFunctionType:\n%s\n%s", indent, "", field, r, args)
+ return fmt.Sprintf("%*s%sFunctionType:%s\n%s\n%s", indent, "", field,
+ forLocalName, r, args)
}
// FunctionParam is a parameter of a function, used for last-specified
@@ -1267,6 +1305,12 @@ type FunctionParam struct {
func (fp *FunctionParam) print(ps *printState) {
if fp.Index == 0 {
ps.writeString("this")
+ } else if ps.llvmStyle {
+ if fp.Index == 1 {
+ ps.writeString("fp")
+ } else {
+ fmt.Fprintf(&ps.buf, "fp%d", fp.Index-2)
+ }
} else {
fmt.Fprintf(&ps.buf, "{parm#%d}", fp.Index)
}
@@ -1422,9 +1466,15 @@ func (vt *VectorType) print(ps *printState) {
}
func (vt *VectorType) printInner(ps *printState) {
- ps.writeString(" __vector(")
+ end := byte(')')
+ if ps.llvmStyle {
+ ps.writeString(" vector[")
+ end = ']'
+ } else {
+ ps.writeString(" __vector(")
+ }
ps.print(vt.Dimension)
- ps.writeByte(')')
+ ps.writeByte(end)
}
func (vt *VectorType) Traverse(fn func(AST) bool) {
@@ -1466,13 +1516,59 @@ func (vt *VectorType) goString(indent int, field string) string {
vt.Base.goString(indent+2, "Base: "))
}
+// ElaboratedType is an elaborated struct/union/enum type.
+type ElaboratedType struct {
+ Kind string
+ Type AST
+}
+
+func (et *ElaboratedType) print(ps *printState) {
+ ps.writeString(et.Kind)
+ ps.writeString(" ")
+ et.Type.print(ps)
+}
+
+func (et *ElaboratedType) Traverse(fn func(AST) bool) {
+ if fn(et) {
+ et.Type.Traverse(fn)
+ }
+}
+
+func (et *ElaboratedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(et) {
+ return nil
+ }
+ typ := et.Type.Copy(fn, skip)
+ if typ == nil {
+ return fn(et)
+ }
+ et = &ElaboratedType{Kind: et.Kind, Type: typ}
+ if r := fn(et); r != nil {
+ return r
+ }
+ return et
+}
+
+func (et *ElaboratedType) GoString() string {
+ return et.goString(0, "")
+}
+
+func (et *ElaboratedType) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sElaboratedtype: Kind: %s\n%s", indent, "", field,
+ et.Kind, et.Type.goString(indent+2, "Expr: "))
+}
+
// Decltype is the decltype operator.
type Decltype struct {
Expr AST
}
func (dt *Decltype) print(ps *printState) {
- ps.writeString("decltype (")
+ ps.writeString("decltype")
+ if !ps.llvmStyle {
+ ps.writeString(" ")
+ }
+ ps.writeString("(")
ps.print(dt.Expr)
ps.writeByte(')')
}
@@ -1544,15 +1640,20 @@ func (op *Operator) goString(indent int, field string) string {
// Constructor is a constructor.
type Constructor struct {
Name AST
+ Base AST // base class of inheriting constructor
}
func (c *Constructor) print(ps *printState) {
ps.print(c.Name)
+ // We don't include the base class in the demangled string.
}
func (c *Constructor) Traverse(fn func(AST) bool) {
if fn(c) {
c.Name.Traverse(fn)
+ if c.Base != nil {
+ c.Base.Traverse(fn)
+ }
}
}
@@ -1561,10 +1662,20 @@ func (c *Constructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
return nil
}
name := c.Name.Copy(fn, skip)
- if name == nil {
+ var base AST
+ if c.Base != nil {
+ base = c.Base.Copy(fn, skip)
+ }
+ if name == nil && base == nil {
return fn(c)
}
- c = &Constructor{Name: name}
+ if name == nil {
+ name = c.Name
+ }
+ if base == nil {
+ base = c.Base
+ }
+ c = &Constructor{Name: name, Base: base}
if r := fn(c); r != nil {
return r
}
@@ -1576,7 +1687,13 @@ func (c *Constructor) GoString() string {
}
func (c *Constructor) goString(indent int, field string) string {
- return fmt.Sprintf("%*s%sConstructor:\n%s", indent, "", field, c.Name.goString(indent+2, "Name: "))
+ var sb strings.Builder
+ fmt.Fprintf(&sb, "%*s%sConstructor:\n", indent, "", field)
+ if c.Base != nil {
+ fmt.Fprintf(&sb, "%s\n", c.Base.goString(indent+2, "Base: "))
+ }
+ fmt.Fprintf(&sb, "%s", c.Name.goString(indent+2, "Name: "))
+ return sb.String()
}
// Destructor is a destructor.
@@ -1727,8 +1844,12 @@ func (pe *PackExpansion) print(ps *printState) {
// We normally only get here if the simplify function was
// unable to locate and expand the pack.
if pe.Pack == nil {
- parenthesize(ps, pe.Base)
- ps.writeString("...")
+ if ps.llvmStyle {
+ ps.print(pe.Base)
+ } else {
+ parenthesize(ps, pe.Base)
+ ps.writeString("...")
+ }
} else {
ps.print(pe.Base)
}
@@ -1834,7 +1955,13 @@ type SizeofPack struct {
}
func (sp *SizeofPack) print(ps *printState) {
- ps.writeString(fmt.Sprintf("%d", len(sp.Pack.Args)))
+ if ps.llvmStyle {
+ ps.writeString("sizeof...(")
+ ps.print(sp.Pack)
+ ps.writeByte(')')
+ } else {
+ ps.writeString(fmt.Sprintf("%d", len(sp.Pack.Args)))
+ }
}
func (sp *SizeofPack) Traverse(fn func(AST) bool) {
@@ -1932,6 +2059,287 @@ func (sa *SizeofArgs) goString(indent int, field string) string {
return fmt.Sprintf("%*s%sSizeofArgs:\n%s", indent, "", field, args)
}
+// TemplateParamName is the name of a template parameter that the
+// demangler introduced for a lambda that has explicit template
+// parameters. This is a prefix with an index.
+type TemplateParamName struct {
+ Prefix string
+ Index int
+}
+
+func (tpn *TemplateParamName) print(ps *printState) {
+ ps.writeString(tpn.Prefix)
+ if tpn.Index > 0 {
+ ps.writeString(fmt.Sprintf("%d", tpn.Index-1))
+ }
+}
+
+func (tpn *TemplateParamName) Traverse(fn func(AST) bool) {
+ fn(tpn)
+}
+
+func (tpn *TemplateParamName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(tpn) {
+ return nil
+ }
+ return fn(tpn)
+}
+
+func (tpn *TemplateParamName) GoString() string {
+ return tpn.goString(0, "")
+}
+
+func (tpn *TemplateParamName) goString(indent int, field string) string {
+ name := tpn.Prefix
+ if tpn.Index > 0 {
+ name += fmt.Sprintf("%d", tpn.Index-1)
+ }
+ return fmt.Sprintf("%*s%sTemplateParamName: %s", indent, "", field, name)
+}
+
+// TypeTemplateParam is a type template parameter that appears in a
+// lambda with explicit template parameters.
+type TypeTemplateParam struct {
+ Name AST
+}
+
+func (ttp *TypeTemplateParam) print(ps *printState) {
+ ps.writeString("typename ")
+ ps.printInner(false)
+ ps.print(ttp.Name)
+}
+
+func (ttp *TypeTemplateParam) Traverse(fn func(AST) bool) {
+ if fn(ttp) {
+ ttp.Name.Traverse(fn)
+ }
+}
+
+func (ttp *TypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(ttp) {
+ return nil
+ }
+ name := ttp.Name.Copy(fn, skip)
+ if name == nil {
+ return fn(ttp)
+ }
+ ttp = &TypeTemplateParam{Name: name}
+ if r := fn(ttp); r != nil {
+ return r
+ }
+ return ttp
+}
+
+func (ttp *TypeTemplateParam) GoString() string {
+ return ttp.goString(0, "")
+}
+
+func (ttp *TypeTemplateParam) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sTypeTemplateParam:\n%s", indent, "", field,
+ ttp.Name.goString(indent+2, "Name"))
+}
+
+// NonTypeTemplateParam is a non-type template parameter that appears
+// in a lambda with explicit template parameters.
+type NonTypeTemplateParam struct {
+ Name AST
+ Type AST
+}
+
+func (nttp *NonTypeTemplateParam) print(ps *printState) {
+ ps.inner = append(ps.inner, nttp)
+ ps.print(nttp.Type)
+ if len(ps.inner) > 0 {
+ ps.writeByte(' ')
+ ps.print(nttp.Name)
+ ps.inner = ps.inner[:len(ps.inner)-1]
+ }
+}
+
+func (nttp *NonTypeTemplateParam) printInner(ps *printState) {
+ ps.print(nttp.Name)
+}
+
+func (nttp *NonTypeTemplateParam) Traverse(fn func(AST) bool) {
+ if fn(nttp) {
+ nttp.Name.Traverse(fn)
+ nttp.Type.Traverse(fn)
+ }
+}
+
+func (nttp *NonTypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(nttp) {
+ return nil
+ }
+ name := nttp.Name.Copy(fn, skip)
+ typ := nttp.Type.Copy(fn, skip)
+ if name == nil && typ == nil {
+ return fn(nttp)
+ }
+ if name == nil {
+ name = nttp.Name
+ }
+ if typ == nil {
+ typ = nttp.Type
+ }
+ nttp = &NonTypeTemplateParam{Name: name, Type: typ}
+ if r := fn(nttp); r != nil {
+ return r
+ }
+ return nttp
+}
+
+func (nttp *NonTypeTemplateParam) GoString() string {
+ return nttp.goString(0, "")
+}
+
+func (nttp *NonTypeTemplateParam) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sNonTypeTemplateParam:\n%s\n%s", indent, "", field,
+ nttp.Name.goString(indent+2, "Name: "),
+ nttp.Type.goString(indent+2, "Type: "))
+}
+
+// TemplateTemplateParam is a template template parameter that appears
+// in a lambda with explicit template parameters.
+type TemplateTemplateParam struct {
+ Name AST
+ Params []AST
+}
+
+func (ttp *TemplateTemplateParam) print(ps *printState) {
+ ps.writeString("template<")
+ for i, param := range ttp.Params {
+ if i > 0 {
+ ps.writeString(", ")
+ }
+ ps.print(param)
+ }
+ ps.writeString("> typename ")
+ ps.print(ttp.Name)
+}
+
+func (ttp *TemplateTemplateParam) Traverse(fn func(AST) bool) {
+ if fn(ttp) {
+ ttp.Name.Traverse(fn)
+ for _, param := range ttp.Params {
+ param.Traverse(fn)
+ }
+ }
+}
+
+func (ttp *TemplateTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(ttp) {
+ return nil
+ }
+
+ changed := false
+
+ name := ttp.Name.Copy(fn, skip)
+ if name == nil {
+ name = ttp.Name
+ } else {
+ changed = true
+ }
+
+ params := make([]AST, len(ttp.Params))
+ for i, p := range ttp.Params {
+ pc := p.Copy(fn, skip)
+ if pc == nil {
+ params[i] = p
+ } else {
+ params[i] = pc
+ changed = true
+ }
+ }
+
+ if !changed {
+ return fn(ttp)
+ }
+
+ ttp = &TemplateTemplateParam{
+ Name: name,
+ Params: params,
+ }
+ if r := fn(ttp); r != nil {
+ return r
+ }
+ return ttp
+}
+
+func (ttp *TemplateTemplateParam) GoString() string {
+ return ttp.goString(0, "")
+}
+
+func (ttp *TemplateTemplateParam) goString(indent int, field string) string {
+ var params strings.Builder
+ fmt.Fprintf(&params, "%*sParams:", indent+2, "")
+ for i, p := range ttp.Params {
+ params.WriteByte('\n')
+ params.WriteString(p.goString(indent+4, fmt.Sprintf("%d: ", i)))
+ }
+ return fmt.Sprintf("%*s%sTemplateTemplateParam:\n%s\n%s", indent, "", field,
+ ttp.Name.goString(indent+2, "Name: "),
+ params.String())
+}
+
+// TemplateParamPack is a template parameter pack that appears in a
+// lambda with explicit template parameters.
+type TemplateParamPack struct {
+ Param AST
+}
+
+func (tpp *TemplateParamPack) print(ps *printState) {
+ holdInner := ps.inner
+ defer func() { ps.inner = holdInner }()
+
+ ps.inner = []AST{tpp}
+ if nttp, ok := tpp.Param.(*NonTypeTemplateParam); ok {
+ ps.print(nttp.Type)
+ } else {
+ ps.print(tpp.Param)
+ }
+ if len(ps.inner) > 0 {
+ ps.writeString("...")
+ }
+}
+
+func (tpp *TemplateParamPack) printInner(ps *printState) {
+ ps.writeString("...")
+ if nttp, ok := tpp.Param.(*NonTypeTemplateParam); ok {
+ ps.print(nttp.Name)
+ }
+}
+
+func (tpp *TemplateParamPack) Traverse(fn func(AST) bool) {
+ if fn(tpp) {
+ tpp.Param.Traverse(fn)
+ }
+}
+
+func (tpp *TemplateParamPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(tpp) {
+ return nil
+ }
+ param := tpp.Param.Copy(fn, skip)
+ if param == nil {
+ return fn(tpp)
+ }
+ tpp = &TemplateParamPack{Param: param}
+ if r := fn(tpp); r != nil {
+ return r
+ }
+ return tpp
+}
+
+func (tpp *TemplateParamPack) GoString() string {
+ return tpp.goString(0, "")
+}
+
+func (tpp *TemplateParamPack) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sTemplateParamPack:\n%s", indent, "", field,
+ tpp.Param.goString(indent+2, "Param: "))
+}
+
// Cast is a type cast.
type Cast struct {
To AST
@@ -1977,7 +2385,11 @@ func (c *Cast) goString(indent int, field string) string {
func parenthesize(ps *printState, val AST) {
paren := false
switch v := val.(type) {
- case *Name, *InitializerList, *FunctionParam:
+ case *Name, *InitializerList:
+ case *FunctionParam:
+ if ps.llvmStyle {
+ paren = true
+ }
case *Qualified:
if v.LocalName {
paren = true
@@ -2047,14 +2459,17 @@ type Unary struct {
}
func (u *Unary) print(ps *printState) {
+ op, _ := u.Op.(*Operator)
expr := u.Expr
// Don't print the argument list when taking the address of a
// function.
- if op, ok := u.Op.(*Operator); ok && op.Name == "&" {
- if t, ok := expr.(*Typed); ok {
- if _, ok := t.Type.(*FunctionType); ok {
- expr = t.Name
+ if !ps.llvmStyle {
+ if op != nil && op.Name == "&" {
+ if t, ok := expr.(*Typed); ok {
+ if _, ok := t.Type.(*FunctionType); ok {
+ expr = t.Name
+ }
}
}
}
@@ -2063,8 +2478,11 @@ func (u *Unary) print(ps *printState) {
parenthesize(ps, expr)
}
- if op, ok := u.Op.(*Operator); ok {
+ if op != nil {
ps.writeString(op.Name)
+ if ps.llvmStyle && op.Name == "noexcept" {
+ ps.writeByte(' ')
+ }
} else if c, ok := u.Op.(*Cast); ok {
ps.writeByte('(')
ps.print(c.To)
@@ -2074,7 +2492,7 @@ func (u *Unary) print(ps *printState) {
}
if !u.Suffix {
- if op, ok := u.Op.(*Operator); ok && op.Name == "::" {
+ if op != nil && op.Name == "::" {
// Don't use parentheses after ::.
ps.print(expr)
} else if u.SizeofType {
@@ -2082,6 +2500,19 @@ func (u *Unary) print(ps *printState) {
ps.writeByte('(')
ps.print(expr)
ps.writeByte(')')
+ } else if op != nil && op.Name == "__alignof__" {
+ // Always use parentheses for __alignof__ argument.
+ ps.writeByte('(')
+ ps.print(expr)
+ ps.writeByte(')')
+ } else if ps.llvmStyle {
+ if op == nil || op.Name != `operator"" ` {
+ ps.writeByte('(')
+ }
+ ps.print(expr)
+ if op == nil || op.Name != `operator"" ` {
+ ps.writeByte(')')
+ }
} else {
parenthesize(ps, expr)
}
@@ -2140,7 +2571,16 @@ func isDesignatedInitializer(x AST) bool {
switch x := x.(type) {
case *Binary:
if op, ok := x.Op.(*Operator); ok {
- return op.Name == "=" || op.Name == "]="
+ if op.Name == "]=" {
+ return true
+ }
+ if op.Name != "=" {
+ return false
+ }
+ if _, ok := x.Left.(*Literal); ok {
+ return false
+ }
+ return true
}
case *Trinary:
if op, ok := x.Op.(*Operator); ok {
@@ -2185,8 +2625,13 @@ func (b *Binary) print(ps *printState) {
// initializer chains.
ps.print(b.Right)
} else {
- ps.writeByte('=')
- parenthesize(ps, b.Right)
+ if ps.llvmStyle {
+ ps.writeString(" = ")
+ ps.print(b.Right)
+ } else {
+ ps.writeByte('=')
+ parenthesize(ps, b.Right)
+ }
}
return
}
@@ -2200,9 +2645,19 @@ func (b *Binary) print(ps *printState) {
left := b.Left
+ skipParens := false
+ skipBothParens := false
+ addSpaces := ps.llvmStyle
+ if ps.llvmStyle && op != nil {
+ switch op.Name {
+ case ".", "->":
+ skipBothParens = true
+ addSpaces = false
+ }
+ }
+
// For a function call in an expression, don't print the types
// of the arguments unless there is a return type.
- skipParens := false
if op != nil && op.Name == "()" {
if ty, ok := b.Left.(*Typed); ok {
if ft, ok := ty.Type.(*FunctionType); ok {
@@ -2215,10 +2670,17 @@ func (b *Binary) print(ps *printState) {
left = ty.Name
}
}
+ if ps.llvmStyle {
+ skipParens = true
+ }
}
- if skipParens {
+ if skipParens || skipBothParens {
ps.print(left)
+ } else if ps.llvmStyle {
+ ps.writeByte('(')
+ ps.print(left)
+ ps.writeByte(')')
} else {
parenthesize(ps, left)
}
@@ -2232,13 +2694,27 @@ func (b *Binary) print(ps *printState) {
if op != nil {
if op.Name != "()" {
+ if addSpaces {
+ ps.writeByte(' ')
+ }
ps.writeString(op.Name)
+ if addSpaces {
+ ps.writeByte(' ')
+ }
}
} else {
ps.print(b.Op)
}
- parenthesize(ps, b.Right)
+ if skipBothParens {
+ ps.print(b.Right)
+ } else if ps.llvmStyle {
+ ps.writeByte('(')
+ ps.print(b.Right)
+ ps.writeByte(')')
+ } else {
+ parenthesize(ps, b.Right)
+ }
if op != nil && op.Name == ">" {
ps.writeByte(')')
@@ -2310,14 +2786,23 @@ func (t *Trinary) print(ps *printState) {
// initializer chains.
ps.print(t.Third)
} else {
- ps.writeByte('=')
- parenthesize(ps, t.Third)
+ if ps.llvmStyle {
+ ps.writeString(" = ")
+ ps.print(t.Third)
+ } else {
+ ps.writeByte('=')
+ parenthesize(ps, t.Third)
+ }
}
return
}
parenthesize(ps, t.First)
- ps.writeByte('?')
+ if ps.llvmStyle {
+ ps.writeString(" ? ")
+ } else {
+ ps.writeByte('?')
+ }
parenthesize(ps, t.Second)
ps.writeString(" : ")
parenthesize(ps, t.Third)
@@ -2386,31 +2871,44 @@ func (f *Fold) print(ps *printState) {
op, _ := f.Op.(*Operator)
printOp := func() {
if op != nil {
+ if ps.llvmStyle {
+ ps.writeByte(' ')
+ }
ps.writeString(op.Name)
+ if ps.llvmStyle {
+ ps.writeByte(' ')
+ }
} else {
ps.print(f.Op)
}
}
+ foldParenthesize := func(a AST) {
+ if _, ok := a.(*ArgumentPack); ok || !ps.llvmStyle {
+ parenthesize(ps, a)
+ } else {
+ ps.print(a)
+ }
+ }
if f.Arg2 == nil {
if f.Left {
ps.writeString("(...")
printOp()
- parenthesize(ps, f.Arg1)
+ foldParenthesize(f.Arg1)
ps.writeString(")")
} else {
ps.writeString("(")
- parenthesize(ps, f.Arg1)
+ foldParenthesize(f.Arg1)
printOp()
ps.writeString("...)")
}
} else {
ps.writeString("(")
- parenthesize(ps, f.Arg1)
+ foldParenthesize(f.Arg1)
printOp()
ps.writeString("...")
printOp()
- parenthesize(ps, f.Arg2)
+ foldParenthesize(f.Arg2)
ps.writeString(")")
}
}
@@ -2471,6 +2969,143 @@ func (f *Fold) goString(indent int, field string) string {
}
}
+// Subobject is a a reference to an offset in an expression. This is
+// used for C++20 manglings of class types used as the type of
+// non-type template arguments.
+//
+// See https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
+type Subobject struct {
+ Type AST
+ SubExpr AST
+ Offset int
+ Selectors []int
+ PastEnd bool
+}
+
+func (so *Subobject) print(ps *printState) {
+ ps.print(so.SubExpr)
+ ps.writeString(".<")
+ ps.print(so.Type)
+ ps.writeString(fmt.Sprintf(" at offset %d>", so.Offset))
+}
+
+func (so *Subobject) Traverse(fn func(AST) bool) {
+ if fn(so) {
+ so.Type.Traverse(fn)
+ so.SubExpr.Traverse(fn)
+ }
+}
+
+func (so *Subobject) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(so) {
+ return nil
+ }
+ typ := so.Type.Copy(fn, skip)
+ subExpr := so.SubExpr.Copy(fn, skip)
+ if typ == nil && subExpr == nil {
+ return nil
+ }
+ if typ == nil {
+ typ = so.Type
+ }
+ if subExpr == nil {
+ subExpr = so.SubExpr
+ }
+ so = &Subobject{
+ Type: typ,
+ SubExpr: subExpr,
+ Offset: so.Offset,
+ Selectors: so.Selectors,
+ PastEnd: so.PastEnd,
+ }
+ if r := fn(so); r != nil {
+ return r
+ }
+ return so
+}
+
+func (so *Subobject) GoString() string {
+ return so.goString(0, "")
+}
+
+func (so *Subobject) goString(indent int, field string) string {
+ var selectors string
+ for _, s := range so.Selectors {
+ selectors += fmt.Sprintf(" %d", s)
+ }
+ return fmt.Sprintf("%*s%sSubobject:\n%s\n%s\n%*sOffset: %d\n%*sSelectors:%s\n%*sPastEnd: %t",
+ indent, "", field,
+ so.Type.goString(indent+2, "Type: "),
+ so.SubExpr.goString(indent+2, "SubExpr: "),
+ indent+2, "", so.Offset,
+ indent+2, "", selectors,
+ indent+2, "", so.PastEnd)
+}
+
+// PtrMemCast is a conversion of an expression to a pointer-to-member
+// type. This is used for C++20 manglings of class types used as the
+// type of non-type template arguments.
+//
+// See https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
+type PtrMemCast struct {
+ Type AST
+ Expr AST
+ Offset int
+}
+
+func (pmc *PtrMemCast) print(ps *printState) {
+ ps.writeString("(")
+ ps.print(pmc.Type)
+ ps.writeString(")(")
+ ps.print(pmc.Expr)
+ ps.writeString(")")
+}
+
+func (pmc *PtrMemCast) Traverse(fn func(AST) bool) {
+ if fn(pmc) {
+ pmc.Type.Traverse(fn)
+ pmc.Expr.Traverse(fn)
+ }
+}
+
+func (pmc *PtrMemCast) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(pmc) {
+ return nil
+ }
+ typ := pmc.Type.Copy(fn, skip)
+ expr := pmc.Expr.Copy(fn, skip)
+ if typ == nil && expr == nil {
+ return nil
+ }
+ if typ == nil {
+ typ = pmc.Type
+ }
+ if expr == nil {
+ expr = pmc.Expr
+ }
+ pmc = &PtrMemCast{
+ Type: typ,
+ Expr: expr,
+ Offset: pmc.Offset,
+ }
+ if r := fn(pmc); r != nil {
+ return r
+ }
+ return pmc
+}
+
+func (pmc *PtrMemCast) GoString() string {
+ return pmc.goString(0, "")
+}
+
+func (pmc *PtrMemCast) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sPtrMemCast:\n%s\n%s\n%*sOffset: %d",
+ indent, "", field,
+ pmc.Type.goString(indent+2, "Type: "),
+ pmc.Expr.goString(indent+2, "Expr: "),
+ indent+2, "", pmc.Offset)
+}
+
// New is a use of operator new in an expression.
type New struct {
Op AST
@@ -2609,7 +3244,11 @@ func (l *Literal) print(ps *printState) {
return
}
} else if b.Name == "decltype(nullptr)" && l.Val == "" {
- ps.print(l.Type)
+ if ps.llvmStyle {
+ ps.writeString("nullptr")
+ } else {
+ ps.print(l.Type)
+ }
return
} else {
isFloat = builtinTypeFloat[b.Name]
@@ -2667,6 +3306,90 @@ func (l *Literal) goString(indent int, field string) string {
indent+2, "", l.Val)
}
+// StringLiteral is a string literal.
+type StringLiteral struct {
+ Type AST
+}
+
+func (sl *StringLiteral) print(ps *printState) {
+ ps.writeString(`"<`)
+ sl.Type.print(ps)
+ ps.writeString(`>"`)
+}
+
+func (sl *StringLiteral) Traverse(fn func(AST) bool) {
+ if fn(sl) {
+ sl.Type.Traverse(fn)
+ }
+}
+
+func (sl *StringLiteral) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(sl) {
+ return nil
+ }
+ typ := sl.Type.Copy(fn, skip)
+ if typ == nil {
+ return fn(sl)
+ }
+ sl = &StringLiteral{Type: typ}
+ if r := fn(sl); r != nil {
+ return r
+ }
+ return sl
+}
+
+func (sl *StringLiteral) GoString() string {
+ return sl.goString(0, "")
+}
+
+func (sl *StringLiteral) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sStringLiteral:\n%s", indent, "", field,
+ sl.Type.goString(indent+2, ""))
+}
+
+// LambdaExpr is a literal that is a lambda expression.
+type LambdaExpr struct {
+ Type AST
+}
+
+func (le *LambdaExpr) print(ps *printState) {
+ ps.writeString("[]")
+ if cl, ok := le.Type.(*Closure); ok {
+ cl.printTypes(ps)
+ }
+ ps.writeString("{...}")
+}
+
+func (le *LambdaExpr) Traverse(fn func(AST) bool) {
+ if fn(le) {
+ le.Type.Traverse(fn)
+ }
+}
+
+func (le *LambdaExpr) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(le) {
+ return nil
+ }
+ typ := le.Type.Copy(fn, skip)
+ if typ == nil {
+ return fn(le)
+ }
+ le = &LambdaExpr{Type: typ}
+ if r := fn(le); r != nil {
+ return r
+ }
+ return le
+}
+
+func (le *LambdaExpr) GoString() string {
+ return le.goString(0, "")
+}
+
+func (le *LambdaExpr) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sLambdaExpr:\n%s", indent, "", field,
+ le.Type.goString(indent+2, ""))
+}
+
// ExprList is a list of expressions, typically arguments to a
// function call in an expression.
type ExprList struct {
@@ -2803,7 +3526,9 @@ type DefaultArg struct {
}
func (da *DefaultArg) print(ps *printState) {
- fmt.Fprintf(&ps.buf, "{default arg#%d}::", da.Num+1)
+ if !ps.llvmStyle {
+ fmt.Fprintf(&ps.buf, "{default arg#%d}::", da.Num+1)
+ }
ps.print(da.Arg)
}
@@ -2839,23 +3564,53 @@ func (da *DefaultArg) goString(indent int, field string) string {
// Closure is a closure, or lambda expression.
type Closure struct {
- Types []AST
- Num int
+ TemplateArgs []AST
+ Types []AST
+ Num int
}
func (cl *Closure) print(ps *printState) {
- ps.writeString("{lambda(")
+ if ps.llvmStyle {
+ if cl.Num == 0 {
+ ps.writeString("'lambda'")
+ } else {
+ ps.writeString(fmt.Sprintf("'lambda%d'", cl.Num-1))
+ }
+ } else {
+ ps.writeString("{lambda")
+ }
+ cl.printTypes(ps)
+ if !ps.llvmStyle {
+ ps.writeString(fmt.Sprintf("#%d}", cl.Num+1))
+ }
+}
+
+func (cl *Closure) printTypes(ps *printState) {
+ if len(cl.TemplateArgs) > 0 {
+ ps.writeString("<")
+ for i, a := range cl.TemplateArgs {
+ if i > 0 {
+ ps.writeString(", ")
+ }
+ ps.print(a)
+ }
+ ps.writeString(">")
+ }
+ ps.writeString("(")
for i, t := range cl.Types {
if i > 0 {
ps.writeString(", ")
}
ps.print(t)
}
- ps.writeString(fmt.Sprintf(")#%d}", cl.Num+1))
+ ps.writeString(")")
}
func (cl *Closure) Traverse(fn func(AST) bool) {
if fn(cl) {
+ for _, a := range cl.TemplateArgs {
+ a.Traverse(fn)
+ }
for _, t := range cl.Types {
t.Traverse(fn)
}
@@ -2866,8 +3621,20 @@ func (cl *Closure) Copy(fn func(AST) AST, skip func(AST) bool) AST {
if skip(cl) {
return nil
}
- types := make([]AST, len(cl.Types))
changed := false
+
+ args := make([]AST, len(cl.TemplateArgs))
+ for i, a := range cl.TemplateArgs {
+ ac := a.Copy(fn, skip)
+ if ac == nil {
+ args[i] = a
+ } else {
+ args[i] = ac
+ changed = true
+ }
+ }
+
+ types := make([]AST, len(cl.Types))
for i, t := range cl.Types {
tc := t.Copy(fn, skip)
if tc == nil {
@@ -2877,10 +3644,11 @@ func (cl *Closure) Copy(fn func(AST) AST, skip func(AST) bool) AST {
changed = true
}
}
+
if !changed {
return fn(cl)
}
- cl = &Closure{Types: types, Num: cl.Num}
+ cl = &Closure{TemplateArgs: args, Types: types, Num: cl.Num}
if r := fn(cl); r != nil {
return r
}
@@ -2892,6 +3660,16 @@ func (cl *Closure) GoString() string {
}
func (cl *Closure) goString(indent int, field string) string {
+ var args string
+ if len(cl.TemplateArgs) == 0 {
+ args = fmt.Sprintf("%*sTemplateArgs: nil", indent+2, "")
+ } else {
+ args = fmt.Sprintf("%*sTemplateArgs:", indent+2, "")
+ for i, a := range cl.TemplateArgs {
+ args += "\n"
+ args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
+ }
+ }
var types string
if len(cl.Types) == 0 {
types = fmt.Sprintf("%*sTypes: nil", indent+2, "")
@@ -2902,7 +3680,71 @@ func (cl *Closure) goString(indent int, field string) string {
types += t.goString(indent+4, fmt.Sprintf("%d: ", i))
}
}
- return fmt.Sprintf("%*s%sClosure: Num: %d\n%s", indent, "", field, cl.Num, types)
+ return fmt.Sprintf("%*s%sClosure: Num: %d\n%s\n%s", indent, "", field,
+ cl.Num, args, types)
+}
+
+// StructuredBindings is a structured binding declaration.
+type StructuredBindings struct {
+ Bindings []AST
+}
+
+func (sb *StructuredBindings) print(ps *printState) {
+ ps.writeString("[")
+ for i, b := range sb.Bindings {
+ if i > 0 {
+ ps.writeString(", ")
+ }
+ b.print(ps)
+ }
+ ps.writeString("]")
+}
+
+func (sb *StructuredBindings) Traverse(fn func(AST) bool) {
+ if fn(sb) {
+ for _, b := range sb.Bindings {
+ b.Traverse(fn)
+ }
+ }
+}
+
+func (sb *StructuredBindings) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(sb) {
+ return nil
+ }
+ changed := false
+ bindings := make([]AST, len(sb.Bindings))
+ for i, b := range sb.Bindings {
+ bc := b.Copy(fn, skip)
+ if bc == nil {
+ bindings[i] = b
+ } else {
+ bindings[i] = bc
+ changed = true
+ }
+ }
+ if !changed {
+ return fn(sb)
+ }
+ sb = &StructuredBindings{Bindings: bindings}
+ if r := fn(sb); r != nil {
+ return r
+ }
+ return sb
+}
+
+func (sb *StructuredBindings) GoString() string {
+ return sb.goString(0, "")
+}
+
+func (sb *StructuredBindings) goString(indent int, field string) string {
+ var strb strings.Builder
+ fmt.Fprintf(&strb, "%*s%sStructuredBinding:", indent, "", field)
+ for _, b := range sb.Bindings {
+ strb.WriteByte('\n')
+ strb.WriteString(b.goString(indent+2, ""))
+ }
+ return strb.String()
}
// UnnamedType is an unnamed type, that just has an index.
@@ -2911,7 +3753,15 @@ type UnnamedType struct {
}
func (ut *UnnamedType) print(ps *printState) {
- ps.writeString(fmt.Sprintf("{unnamed type#%d}", ut.Num+1))
+ if ps.llvmStyle {
+ if ut.Num == 0 {
+ ps.writeString("'unnamed'")
+ } else {
+ ps.writeString(fmt.Sprintf("'unnamed%d'", ut.Num-1))
+ }
+ } else {
+ ps.writeString(fmt.Sprintf("{unnamed type#%d}", ut.Num+1))
+ }
}
func (ut *UnnamedType) Traverse(fn func(AST) bool) {
@@ -2941,7 +3791,13 @@ type Clone struct {
func (c *Clone) print(ps *printState) {
ps.print(c.Base)
- ps.writeString(fmt.Sprintf(" [clone %s]", c.Suffix))
+ if ps.llvmStyle {
+ ps.writeString(" (")
+ ps.writeString(c.Suffix)
+ ps.writeByte(')')
+ } else {
+ ps.writeString(fmt.Sprintf(" [clone %s]", c.Suffix))
+ }
}
func (c *Clone) Traverse(fn func(AST) bool) {
@@ -2982,7 +3838,16 @@ type Special struct {
}
func (s *Special) print(ps *printState) {
- ps.writeString(s.Prefix)
+ prefix := s.Prefix
+ if ps.llvmStyle {
+ switch prefix {
+ case "TLS wrapper function for ":
+ prefix = "thread-local wrapper routine for "
+ case "TLS init function for ":
+ prefix = "thread-local initialization routine for "
+ }
+ }
+ ps.writeString(prefix)
ps.print(s.Val)
}
@@ -3194,7 +4059,12 @@ func (ps *printState) printOneInner(save *[]AST) {
func (ps *printState) isEmpty(a AST) bool {
switch a := a.(type) {
case *ArgumentPack:
- return len(a.Args) == 0
+ for _, a := range a.Args {
+ if !ps.isEmpty(a) {
+ return false
+ }
+ }
+ return true
case *ExprList:
return len(a.Exprs) == 0
case *PackExpansion:
diff --git a/vendor/github.com/ianlancetaylor/demangle/demangle.go b/vendor/github.com/ianlancetaylor/demangle/demangle.go
index c2667446d..9eec0aa3c 100644
--- a/vendor/github.com/ianlancetaylor/demangle/demangle.go
+++ b/vendor/github.com/ianlancetaylor/demangle/demangle.go
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package demangle defines functions that demangle GCC/LLVM C++ symbol names.
+// Package demangle defines functions that demangle GCC/LLVM
+// C++ and Rust symbol names.
// This package recognizes names that were mangled according to the C++ ABI
-// defined at http://codesourcery.com/cxx-abi/.
+// defined at http://codesourcery.com/cxx-abi/ and the Rust ABI
+// defined at
+// https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html
//
// Most programs will want to call Filter or ToString.
package demangle
@@ -17,7 +20,7 @@ import (
// ErrNotMangledName is returned by CheckedDemangle if the string does
// not appear to be a C++ symbol name.
-var ErrNotMangledName = errors.New("not a C++ mangled name")
+var ErrNotMangledName = errors.New("not a C++ or Rust mangled name")
// Option is the type of demangler options.
type Option int
@@ -33,11 +36,23 @@ const (
// NoParams implies NoClones.
NoClones
+ // The NoRust option disables demangling of old-style Rust
+ // mangled names, which can be confused with C++ style mangled
+ // names. New style Rust mangled names are still recognized.
+ NoRust
+
// The Verbose option turns on more verbose demangling.
Verbose
+
+ // LLVMStyle tries to translate an AST to a string in the
+ // style of the LLVM demangler. This does not affect
+ // the parsing of the AST, only the conversion of the AST
+ // to a string.
+ LLVMStyle
)
-// Filter demangles a C++ symbol name, returning the human-readable C++ name.
+// Filter demangles a C++ or Rust symbol name,
+// returning the human-readable C++ or Rust name.
// If any error occurs during demangling, the input string is returned.
func Filter(name string, options ...Option) string {
ret, err := ToString(name, options...)
@@ -47,11 +62,34 @@ func Filter(name string, options ...Option) string {
return ret
}
-// ToString demangles a C++ symbol name, returning a human-readable C++
-// name or an error.
-// If the name does not appear to be a C++ symbol name at all, the
-// error will be ErrNotMangledName.
+// ToString demangles a C++ or Rust symbol name,
+// returning a human-readable C++ or Rust name or an error.
+// If the name does not appear to be a C++ or Rust symbol name at all,
+// the error will be ErrNotMangledName.
func ToString(name string, options ...Option) (string, error) {
+ if strings.HasPrefix(name, "_R") {
+ return rustToString(name, options)
+ }
+
+ // Check for an old-style Rust mangled name.
+ // It starts with _ZN and ends with "17h" followed by 16 hex digits
+ // followed by "E".
+ if strings.HasPrefix(name, "_ZN") && strings.HasSuffix(name, "E") && len(name) > 23 && name[len(name)-20:len(name)-17] == "17h" {
+ noRust := false
+ for _, o := range options {
+ if o == NoRust {
+ noRust = true
+ break
+ }
+ }
+ if !noRust {
+ s, ok := oldRustToString(name, options)
+ if ok {
+ return s, nil
+ }
+ }
+ }
+
a, err := ToAST(name, options...)
if err != nil {
return "", err
@@ -65,12 +103,37 @@ func ToString(name string, options ...Option) (string, error) {
// the parameter types are not demangled.
// If the name does not appear to be a C++ symbol name at all, the
// error will be ErrNotMangledName.
+// This function does not currently support Rust symbol names.
func ToAST(name string, options ...Option) (AST, error) {
if strings.HasPrefix(name, "_Z") {
a, err := doDemangle(name[2:], options...)
return a, adjustErr(err, 2)
}
+ if strings.HasPrefix(name, "___Z") {
+ // clang extensions
+ block := strings.LastIndex(name, "_block_invoke")
+ if block == -1 {
+ return nil, ErrNotMangledName
+ }
+ a, err := doDemangle(name[4:block], options...)
+ if err != nil {
+ return a, adjustErr(err, 4)
+ }
+ name = strings.TrimPrefix(name[block:], "_block_invoke")
+ if len(name) > 0 && name[0] == '_' {
+ name = name[1:]
+ }
+ for len(name) > 0 && isDigit(name[0]) {
+ name = name[1:]
+ }
+ if len(name) > 0 && name[0] != '.' {
+ return nil, errors.New("unparsed characters at end of mangled name")
+ }
+ a = &Special{Prefix: "invocation function for block in ", Val: a}
+ return a, nil
+ }
+
const prefix = "_GLOBAL_"
if strings.HasPrefix(name, prefix) {
// The standard demangler ignores NoParams for global
@@ -150,12 +213,13 @@ func doDemangle(name string, options ...Option) (ret AST, err error) {
case NoParams:
params = false
clones = false
- case NoTemplateParams:
- // This is a valid option but only affect printing of the AST.
case NoClones:
clones = false
case Verbose:
verbose = true
+ case NoTemplateParams, LLVMStyle:
+ // These are valid options but only affect
+ // printing of the AST.
default:
return nil, fmt.Errorf("unrecognized demangler option %v", o)
}
@@ -185,7 +249,16 @@ type state struct {
off int // offset of str within original string
subs substitutions // substitutions
templates []*Template // templates being processed
- inLambda int // number of lambdas being parsed
+
+ // The number of entries in templates when we started parsing
+ // a lambda, plus 1 so that 0 means not parsing a lambda.
+ lambdaTemplateLevel int
+
+ // Counts of template parameters without template arguments,
+ // for lambdas.
+ typeTemplateParamCount int
+ nonTypeTemplateParamCount int
+ templateTemplateParamCount int
}
// copy returns a copy of the current state.
@@ -308,35 +381,40 @@ func (st *state) encoding(params bool, local forLocalNameType) AST {
return a
}
- check := a
- mwq, _ := check.(*MethodWithQualifiers)
- if mwq != nil {
- check = mwq.Method
- }
+ mwq, _ := a.(*MethodWithQualifiers)
- var template *Template
- switch check := check.(type) {
- case *Template:
- template = check
- case *Qualified:
- if check.LocalName {
- n := check.Name
- if nmwq, ok := n.(*MethodWithQualifiers); ok {
- n = nmwq.Method
+ var findTemplate func(AST) *Template
+ findTemplate = func(check AST) *Template {
+ switch check := check.(type) {
+ case *Template:
+ return check
+ case *Qualified:
+ if check.LocalName {
+ return findTemplate(check.Name)
+ } else if _, ok := check.Name.(*Constructor); ok {
+ return findTemplate(check.Name)
+ }
+ case *MethodWithQualifiers:
+ return findTemplate(check.Method)
+ case *Constructor:
+ if check.Base != nil {
+ return findTemplate(check.Base)
}
- template, _ = n.(*Template)
}
+ return nil
}
- var oldInLambda int
+
+ template := findTemplate(a)
+ var oldLambdaTemplateLevel int
if template != nil {
st.templates = append(st.templates, template)
- oldInLambda = st.inLambda
- st.inLambda = 0
+ oldLambdaTemplateLevel = st.lambdaTemplateLevel
+ st.lambdaTemplateLevel = 0
}
// Checking for the enable_if attribute here is what the LLVM
// demangler does. This is not very general but perhaps it is
- // sufficent.
+ // sufficient.
const enableIfPrefix = "Ua9enable_ifI"
var enableIfArgs []AST
if strings.HasPrefix(st.str, enableIfPrefix) {
@@ -348,7 +426,7 @@ func (st *state) encoding(params bool, local forLocalNameType) AST {
if template != nil {
st.templates = st.templates[:len(st.templates)-1]
- st.inLambda = oldInLambda
+ st.lambdaTemplateLevel = oldLambdaTemplateLevel
}
ft = simplify(ft)
@@ -357,7 +435,7 @@ func (st *state) encoding(params bool, local forLocalNameType) AST {
// doesn't get confused with the top level return type.
if local == forLocalName {
if functype, ok := ft.(*FunctionType); ok {
- functype.Return = nil
+ functype.ForLocalName = true
}
}
@@ -573,7 +651,7 @@ func (st *state) prefix() AST {
var next AST
c := st.str[0]
- if isDigit(c) || isLower(c) || c == 'U' || c == 'L' {
+ if isDigit(c) || isLower(c) || c == 'U' || c == 'L' || (c == 'D' && len(st.str) > 1 && st.str[1] == 'C') {
un, isUnCast := st.unqualifiedName()
next = un
if isUnCast {
@@ -595,10 +673,17 @@ func (st *state) prefix() AST {
st.fail("constructor before name is seen")
}
st.advance(1)
+ var base AST
if inheriting {
- last = st.demangleType(false)
+ base = st.demangleType(false)
+ }
+ next = &Constructor{
+ Name: getLast(last),
+ Base: base,
+ }
+ if len(st.str) > 0 && st.str[0] == 'B' {
+ next = st.taggedName(next)
}
- next = &Constructor{Name: getLast(last)}
case 'D':
if len(st.str) > 1 && (st.str[1] == 'T' || st.str[1] == 't') {
next = st.demangleType(false)
@@ -611,6 +696,9 @@ func (st *state) prefix() AST {
}
st.advance(2)
next = &Destructor{Name: getLast(last)}
+ if len(st.str) > 0 && st.str[0] == 'B' {
+ next = st.taggedName(next)
+ }
}
case 'S':
next = st.substitution(true)
@@ -713,6 +801,18 @@ func (st *state) unqualifiedName() (r AST, isCast bool) {
n := st.sourceName()
a = &Unary{Op: op, Expr: n, Suffix: false, SizeofType: false}
}
+ } else if c == 'D' && len(st.str) > 1 && st.str[1] == 'C' {
+ var bindings []AST
+ st.advance(2)
+ for {
+ binding := st.sourceName()
+ bindings = append(bindings, binding)
+ if len(st.str) > 0 && st.str[0] == 'E' {
+ st.advance(1)
+ break
+ }
+ }
+ a = &StructuredBindings{Bindings: bindings}
} else {
switch c {
case 'C', 'D':
@@ -728,6 +828,10 @@ func (st *state) unqualifiedName() (r AST, isCast bool) {
}
c := st.str[1]
switch c {
+ case 'b':
+ st.advance(2)
+ st.compactNumber()
+ a = &Name{Name: "'block-literal'"}
case 'l':
a = st.closureTypeName()
case 't':
@@ -802,6 +906,42 @@ func (st *state) number() int {
return val
}
+// <seq-id> ::= <0-9A-Z>+
+//
+// We expect this to be followed by an underscore.
+func (st *state) seqID(eofOK bool) int {
+ if len(st.str) > 0 && st.str[0] == '_' {
+ st.advance(1)
+ return 0
+ }
+ id := 0
+ for {
+ if len(st.str) == 0 {
+ if eofOK {
+ return id + 1
+ }
+ st.fail("missing end to sequence ID")
+ }
+ // Don't overflow a 32-bit int.
+ if id >= 0x80000000/36-36 {
+ st.fail("sequence ID overflow")
+ }
+ c := st.str[0]
+ if c == '_' {
+ st.advance(1)
+ return id + 1
+ }
+ if isDigit(c) {
+ id = id*36 + int(c-'0')
+ } else if isUpper(c) {
+ id = id*36 + int(c-'A') + 10
+ } else {
+ st.fail("invalid character in sequence ID")
+ }
+ st.advance(1)
+ }
+}
+
// An operator is the demangled name, and the number of arguments it
// takes in an expression.
type operator struct {
@@ -864,6 +1004,7 @@ var operators = map[string]operator{
"ng": {"-", 1},
"nt": {"!", 1},
"nw": {"new", 3},
+ "nx": {"noexcept", 1},
"oR": {"|=", 2},
"oo": {"||", 2},
"or": {"|", 2},
@@ -1094,8 +1235,8 @@ func (st *state) specialName() AST {
return &Special{Prefix: "guard variable for ", Val: n}
case 'R':
n := st.name()
- i := st.number()
- return &Special{Prefix: fmt.Sprintf("reference temporary #%d for ", i), Val: n}
+ st.seqID(true)
+ return &Special{Prefix: "reference temporary for ", Val: n}
case 'A':
v := st.encoding(true, notForLocalName)
return &Special{Prefix: "hidden alias for ", Val: v}
@@ -1257,6 +1398,23 @@ func (st *state) demangleType(isCast bool) AST {
case 'M':
ret = st.pointerToMemberType(isCast)
case 'T':
+ if len(st.str) > 1 && (st.str[1] == 's' || st.str[1] == 'u' || st.str[1] == 'e') {
+ c = st.str[1]
+ st.advance(2)
+ ret = st.name()
+ var kind string
+ switch c {
+ case 's':
+ kind = "struct"
+ case 'u':
+ kind = "union"
+ case 'e':
+ kind = "enum"
+ }
+ ret = &ElaboratedType{Kind: kind, Type: ret}
+ break
+ }
+
ret = st.templateParam()
if len(st.str) > 0 && st.str[0] == 'I' {
// See the function comment to explain this.
@@ -1681,7 +1839,11 @@ func (st *state) bareFunctionType(hasReturnType bool) AST {
returnType = st.demangleType(false)
}
types := st.parmlist()
- return &FunctionType{Return: returnType, Args: types}
+ return &FunctionType{
+ Return: returnType,
+ Args: types,
+ ForLocalName: false, // may be set later in encoding
+ }
}
// <array-type> ::= A <(positive dimension) number> _ <(element) type>
@@ -1798,6 +1960,8 @@ func (st *state) compactNumber() int {
// <template-param> ::= T_
// ::= T <(parameter-2 non-negative) number> _
+// ::= TL <level-1> __
+// ::= TL <level-1> _ <parameter-2 non-negative number> _
//
// When a template parameter is a substitution candidate, any
// reference to that substitution refers to the template parameter
@@ -1805,22 +1969,27 @@ func (st *state) compactNumber() int {
// whatever the template parameter would be expanded to here. We sort
// this out in substitution and simplify.
func (st *state) templateParam() AST {
- if len(st.templates) == 0 && st.inLambda == 0 {
- st.fail("template parameter not in scope of template")
- }
off := st.off
-
st.checkChar('T')
+
+ level := 0
+ if len(st.str) > 0 && st.str[0] == 'L' {
+ st.advance(1)
+ level = st.compactNumber()
+ }
+
n := st.compactNumber()
- if st.inLambda > 0 {
- // g++ mangles lambda auto params as template params.
- // Apparently we can't encounter a template within a lambda.
- // See https://gcc.gnu.org/PR78252.
- return &LambdaAuto{Index: n}
+ if level >= len(st.templates) {
+ if st.lambdaTemplateLevel > 0 && level == st.lambdaTemplateLevel-1 {
+ // Lambda auto params are mangled as template params.
+ // See https://gcc.gnu.org/PR78252.
+ return &LambdaAuto{Index: n}
+ }
+ st.failEarlier(fmt.Sprintf("template parameter is not in scope of template (level %d >= %d)", level, len(st.templates)), st.off-off)
}
- template := st.templates[len(st.templates)-1]
+ template := st.templates[level]
if template == nil {
// We are parsing a cast operator. If the cast is
@@ -1830,6 +1999,11 @@ func (st *state) templateParam() AST {
}
if n >= len(template.Args) {
+ if st.lambdaTemplateLevel > 0 && level == st.lambdaTemplateLevel-1 {
+ // Lambda auto params are mangled as template params.
+ // See https://gcc.gnu.org/PR78252.
+ return &LambdaAuto{Index: n}
+ }
st.failEarlier(fmt.Sprintf("template index out of range (%d >= %d)", n, len(template.Args)), st.off-off)
}
@@ -1968,9 +2142,11 @@ func (st *state) exprList(stop byte) AST {
// ::= dc <type> <expression>
// ::= sc <type> <expression>
// ::= cc <type> <expression>
+// ::= mc <parameter type> <expr> [<offset number>] E
// ::= rc <type> <expression>
// ::= ti <type>
// ::= te <expression>
+// ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
// ::= st <type>
// ::= sz <expression>
// ::= at <type>
@@ -1991,6 +2167,7 @@ func (st *state) exprList(stop byte) AST {
// ::= fR <binary operator-name> <expression> <expression>
// ::= tw <expression>
// ::= tr
+// ::= u <source-name> <template-arg>* E
// ::= <unresolved-name>
// ::= <expr-primary>
//
@@ -2013,6 +2190,9 @@ func (st *state) expression() AST {
return st.exprPrimary()
} else if st.str[0] == 'T' {
return st.templateParam()
+ } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'o' {
+ st.advance(2)
+ return st.subobject()
} else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'r' {
return st.unresolvedName()
} else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'p' {
@@ -2063,6 +2243,23 @@ func (st *state) expression() AST {
st.cvQualifiers()
index := st.compactNumber()
return &FunctionParam{Index: index + 1}
+ } else if st.str[0] == 'm' && len(st.str) > 1 && st.str[1] == 'c' {
+ st.advance(2)
+ typ := st.demangleType(false)
+ expr := st.expression()
+ offset := 0
+ if len(st.str) > 0 && (st.str[0] == 'n' || isDigit(st.str[0])) {
+ offset = st.number()
+ }
+ if len(st.str) == 0 || st.str[0] != 'E' {
+ st.fail("expected E after pointer-to-member conversion")
+ }
+ st.advance(1)
+ return &PtrMemCast{
+ Type: typ,
+ Expr: expr,
+ Offset: offset,
+ }
} else if isDigit(st.str[0]) || (st.str[0] == 'o' && len(st.str) > 1 && st.str[1] == 'n') {
if st.str[0] == 'o' {
// Skip operator function ID.
@@ -2088,6 +2285,50 @@ func (st *state) expression() AST {
o, _ := st.operatorName(true)
t := st.demangleType(false)
return &Unary{Op: o, Expr: t, Suffix: false, SizeofType: true}
+ } else if st.str[0] == 'u' {
+ st.advance(1)
+ name := st.sourceName()
+ // Special case __uuidof followed by type or
+ // expression, as used by LLVM.
+ if n, ok := name.(*Name); ok && n.Name == "__uuidof" {
+ if len(st.str) < 2 {
+ st.fail("missing uuidof argument")
+ }
+ var operand AST
+ if st.str[0] == 't' {
+ st.advance(1)
+ operand = st.demangleType(false)
+ } else if st.str[0] == 'z' {
+ st.advance(1)
+ operand = st.expression()
+ }
+ if operand != nil {
+ return &Binary{
+ Op: &Operator{Name: "()"},
+ Left: name,
+ Right: &ExprList{
+ Exprs: []AST{operand},
+ },
+ }
+ }
+ }
+ var args []AST
+ for {
+ if len(st.str) == 0 {
+ st.fail("missing argument in vendor extended expressoin")
+ }
+ if st.str[0] == 'E' {
+ st.advance(1)
+ break
+ }
+ arg := st.templateArg()
+ args = append(args, arg)
+ }
+ return &Binary{
+ Op: &Operator{Name: "()"},
+ Left: name,
+ Right: &ExprList{Exprs: args},
+ }
} else {
if len(st.str) < 2 {
st.fail("missing operator code")
@@ -2185,6 +2426,42 @@ func (st *state) expression() AST {
}
}
+// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
+// <union-selector> ::= _ [<number>]
+func (st *state) subobject() AST {
+ typ := st.demangleType(false)
+ expr := st.expression()
+ offset := 0
+ if len(st.str) > 0 && (st.str[0] == 'n' || isDigit(st.str[0])) {
+ offset = st.number()
+ }
+ var selectors []int
+ for len(st.str) > 0 && st.str[0] == '_' {
+ st.advance(1)
+ selector := 0
+ if len(st.str) > 0 && (st.str[0] == 'n' || isDigit(st.str[0])) {
+ selector = st.number()
+ }
+ selectors = append(selectors, selector)
+ }
+ pastEnd := false
+ if len(st.str) > 0 && st.str[0] == 'p' {
+ st.advance(1)
+ pastEnd = true
+ }
+ if len(st.str) == 0 || st.str[0] != 'E' {
+ st.fail("expected E after subobject")
+ }
+ st.advance(1)
+ return &Subobject{
+ Type: typ,
+ SubExpr: expr,
+ Offset: offset,
+ Selectors: selectors,
+ PastEnd: pastEnd,
+ }
+}
+
// <unresolved-name> ::= [gs] <base-unresolved-name>
// ::= sr <unresolved-type> <base-unresolved-name>
// ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
@@ -2320,6 +2597,14 @@ func (st *state) exprPrimary() AST {
} else {
t := st.demangleType(false)
+ isArrayType := func(typ AST) bool {
+ if twq, ok := typ.(*TypeWithQualifiers); ok {
+ typ = twq.Base
+ }
+ _, ok := typ.(*ArrayType)
+ return ok
+ }
+
neg := false
if len(st.str) > 0 && st.str[0] == 'n' {
neg = true
@@ -2331,6 +2616,13 @@ func (st *state) exprPrimary() AST {
// We accept one if present because GCC
// used to generate one.
// https://gcc.gnu.org/PR91979.
+ } else if cl, ok := t.(*Closure); ok {
+ // A closure doesn't have a value.
+ st.advance(1)
+ return &LambdaExpr{Type: cl}
+ } else if isArrayType(t) {
+ st.advance(1)
+ return &StringLiteral{Type: t}
} else {
st.fail("missing literal value")
}
@@ -2354,6 +2646,15 @@ func (st *state) exprPrimary() AST {
// __ <(non-negative) number> _ (when number >= 10)
func (st *state) discriminator(a AST) AST {
if len(st.str) == 0 || st.str[0] != '_' {
+ // clang can generate a discriminator at the end of
+ // the string with no underscore.
+ for i := 0; i < len(st.str); i++ {
+ if !isDigit(st.str[i]) {
+ return a
+ }
+ }
+ // Skip the trailing digits.
+ st.advance(len(st.str))
return a
}
off := st.off
@@ -2379,18 +2680,131 @@ func (st *state) discriminator(a AST) AST {
}
// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+// <lambda-sig> ::= <parameter type>+
func (st *state) closureTypeName() AST {
st.checkChar('U')
st.checkChar('l')
- st.inLambda++
+
+ oldLambdaTemplateLevel := st.lambdaTemplateLevel
+ st.lambdaTemplateLevel = len(st.templates) + 1
+
+ var templateArgs []AST
+ var template *Template
+ for len(st.str) > 1 && st.str[0] == 'T' {
+ arg, templateVal := st.templateParamDecl()
+ if arg == nil {
+ break
+ }
+ templateArgs = append(templateArgs, arg)
+ if template == nil {
+ template = &Template{
+ Name: &Name{Name: "lambda"},
+ }
+ st.templates = append(st.templates, template)
+ }
+ template.Args = append(template.Args, templateVal)
+ }
+
types := st.parmlist()
- st.inLambda--
+
+ st.lambdaTemplateLevel = oldLambdaTemplateLevel
+
+ if template != nil {
+ st.templates = st.templates[:len(st.templates)-1]
+ }
+
if len(st.str) == 0 || st.str[0] != 'E' {
st.fail("expected E after closure type name")
}
st.advance(1)
num := st.compactNumber()
- return &Closure{Types: types, Num: num}
+ return &Closure{TemplateArgs: templateArgs, Types: types, Num: num}
+}
+
+// <template-param-decl> ::= Ty # type parameter
+// ::= Tn <type> # non-type parameter
+// ::= Tt <template-param-decl>* E # template parameter
+// ::= Tp <template-param-decl> # parameter pack
+//
+// Returns the new AST to include in the AST we are building and the
+// new AST to add to the list of template parameters.
+//
+// Returns nil, nil if not looking at a template-param-decl.
+func (st *state) templateParamDecl() (AST, AST) {
+ if len(st.str) < 2 || st.str[0] != 'T' {
+ return nil, nil
+ }
+ mk := func(prefix string, p *int) AST {
+ idx := *p
+ (*p)++
+ return &TemplateParamName{
+ Prefix: prefix,
+ Index: idx,
+ }
+ }
+ switch st.str[1] {
+ case 'y':
+ st.advance(2)
+ name := mk("$T", &st.typeTemplateParamCount)
+ tp := &TypeTemplateParam{
+ Name: name,
+ }
+ return tp, name
+ case 'n':
+ st.advance(2)
+ name := mk("$N", &st.nonTypeTemplateParamCount)
+ typ := st.demangleType(false)
+ tp := &NonTypeTemplateParam{
+ Name: name,
+ Type: typ,
+ }
+ return tp, name
+ case 't':
+ st.advance(2)
+ name := mk("$TT", &st.templateTemplateParamCount)
+ var params []AST
+ var template *Template
+ for {
+ if len(st.str) == 0 {
+ st.fail("expected closure template parameter")
+ }
+ if st.str[0] == 'E' {
+ st.advance(1)
+ break
+ }
+ off := st.off
+ param, templateVal := st.templateParamDecl()
+ if param == nil {
+ st.failEarlier("expected closure template parameter", st.off-off)
+ }
+ params = append(params, param)
+ if template == nil {
+ template = &Template{
+ Name: &Name{Name: "template_template"},
+ }
+ st.templates = append(st.templates, template)
+ }
+ template.Args = append(template.Args, templateVal)
+ }
+ if template != nil {
+ st.templates = st.templates[:len(st.templates)-1]
+ }
+ tp := &TemplateTemplateParam{
+ Name: name,
+ Params: params,
+ }
+ return tp, name
+ case 'p':
+ st.advance(2)
+ off := st.off
+ param, templateVal := st.templateParamDecl()
+ if param == nil {
+ st.failEarlier("expected lambda template parameter", st.off-off)
+ }
+ return &TemplateParamPack{Param: param}, templateVal
+ default:
+ return nil, nil
+ }
}
// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
@@ -2504,36 +2918,11 @@ func (st *state) substitution(forPrefix bool) AST {
st.fail("missing substitution index")
}
c := st.str[0]
- st.advance(1)
- dec := 1
+ off := st.off
if c == '_' || isDigit(c) || isUpper(c) {
- id := 0
- if c != '_' {
- for c != '_' {
- // Don't overflow a 32-bit int.
- if id >= 0x80000000/36-36 {
- st.fail("substitution index overflow")
- }
- if isDigit(c) {
- id = id*36 + int(c-'0')
- } else if isUpper(c) {
- id = id*36 + int(c-'A') + 10
- } else {
- st.fail("invalid character in substitution index")
- }
-
- if len(st.str) == 0 {
- st.fail("missing end to substitution index")
- }
- c = st.str[0]
- st.advance(1)
- dec++
- }
- id++
- }
-
+ id := st.seqID(false)
if id >= len(st.subs) {
- st.failEarlier(fmt.Sprintf("substitution index out of range (%d >= %d)", id, len(st.subs)), dec)
+ st.failEarlier(fmt.Sprintf("substitution index out of range (%d >= %d)", id, len(st.subs)), st.off-off)
}
ret := st.subs[id]
@@ -2545,18 +2934,18 @@ func (st *state) substitution(forPrefix bool) AST {
// When copying a Typed we may need to adjust
// the templates.
copyTemplates := st.templates
- var oldInLambda []int
+ var oldLambdaTemplateLevel []int
// pushTemplate is called from skip, popTemplate from copy.
pushTemplate := func(template *Template) {
copyTemplates = append(copyTemplates, template)
- oldInLambda = append(oldInLambda, st.inLambda)
- st.inLambda = 0
+ oldLambdaTemplateLevel = append(oldLambdaTemplateLevel, st.lambdaTemplateLevel)
+ st.lambdaTemplateLevel = 0
}
popTemplate := func() {
copyTemplates = copyTemplates[:len(copyTemplates)-1]
- st.inLambda = oldInLambda[len(oldInLambda)-1]
- oldInLambda = oldInLambda[:len(oldInLambda)-1]
+ st.lambdaTemplateLevel = oldLambdaTemplateLevel[len(oldLambdaTemplateLevel)-1]
+ oldLambdaTemplateLevel = oldLambdaTemplateLevel[:len(oldLambdaTemplateLevel)-1]
}
copy := func(a AST) AST {
@@ -2569,8 +2958,9 @@ func (st *state) substitution(forPrefix bool) AST {
}
return nil
case *Closure:
- // Undo the decrement in skip.
- st.inLambda--
+ // Undo the save in skip.
+ st.lambdaTemplateLevel = oldLambdaTemplateLevel[len(oldLambdaTemplateLevel)-1]
+ oldLambdaTemplateLevel = oldLambdaTemplateLevel[:len(oldLambdaTemplateLevel)-1]
return nil
case *TemplateParam:
index = a.Index
@@ -2582,7 +2972,7 @@ func (st *state) substitution(forPrefix bool) AST {
default:
return nil
}
- if st.inLambda > 0 {
+ if st.lambdaTemplateLevel > 0 {
if _, ok := a.(*LambdaAuto); ok {
return nil
}
@@ -2598,7 +2988,7 @@ func (st *state) substitution(forPrefix bool) AST {
// here.
template = rt
} else {
- st.failEarlier("substituted template parameter not in scope of template", dec)
+ st.failEarlier("substituted template parameter not in scope of template", st.off-off)
}
if template == nil {
// This template parameter is within
@@ -2607,7 +2997,7 @@ func (st *state) substitution(forPrefix bool) AST {
}
if index >= len(template.Args) {
- st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", index, len(template.Args)), dec)
+ st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", index, len(template.Args)), st.off-off)
}
return &TemplateParam{Index: index, Template: template}
@@ -2622,8 +3012,9 @@ func (st *state) substitution(forPrefix bool) AST {
}
return false
case *Closure:
- // This is decremented in copy.
- st.inLambda++
+ // This is undone in copy.
+ oldLambdaTemplateLevel = append(oldLambdaTemplateLevel, st.lambdaTemplateLevel)
+ st.lambdaTemplateLevel = len(copyTemplates) + 1
return false
case *TemplateParam, *LambdaAuto:
return false
@@ -2643,6 +3034,7 @@ func (st *state) substitution(forPrefix bool) AST {
return ret
} else {
+ st.advance(1)
m := subAST
if st.verbose {
m = verboseAST
diff --git a/vendor/github.com/ianlancetaylor/demangle/go.mod b/vendor/github.com/ianlancetaylor/demangle/go.mod
new file mode 100644
index 000000000..0a721337d
--- /dev/null
+++ b/vendor/github.com/ianlancetaylor/demangle/go.mod
@@ -0,0 +1,3 @@
+module github.com/ianlancetaylor/demangle
+
+go 1.12
diff --git a/vendor/github.com/ianlancetaylor/demangle/rust.go b/vendor/github.com/ianlancetaylor/demangle/rust.go
new file mode 100644
index 000000000..140b63164
--- /dev/null
+++ b/vendor/github.com/ianlancetaylor/demangle/rust.go
@@ -0,0 +1,1069 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package demangle
+
+import (
+ "fmt"
+ "math"
+ "math/bits"
+ "strings"
+ "unicode/utf8"
+)
+
+// rustToString demangles a Rust symbol.
+func rustToString(name string, options []Option) (ret string, err error) {
+ if !strings.HasPrefix(name, "_R") {
+ return "", ErrNotMangledName
+ }
+
+ // When the demangling routines encounter an error, they panic
+ // with a value of type demangleErr.
+ defer func() {
+ if r := recover(); r != nil {
+ if de, ok := r.(demangleErr); ok {
+ ret = ""
+ err = de
+ return
+ }
+ panic(r)
+ }
+ }()
+
+ suffix := ""
+ dot := strings.Index(name, ".")
+ if dot >= 0 {
+ suffix = name[dot:]
+ name = name[:dot]
+ }
+
+ name = name[2:]
+ rst := &rustState{orig: name, str: name}
+ rst.symbolName()
+
+ if len(rst.str) > 0 {
+ rst.fail("unparsed characters at end of mangled name")
+ }
+
+ if suffix != "" {
+ rst.skip = false
+ rst.writeString(" (")
+ rst.writeString(suffix)
+ rst.writeByte(')')
+ }
+
+ return rst.buf.String(), nil
+}
+
+// A rustState holds the current state of demangling a Rust string.
+type rustState struct {
+ orig string // the original string being demangled
+ str string // remainder of string to demangle
+ off int // offset of str within original string
+ buf strings.Builder // demangled string being built
+ skip bool // don't print, just skip
+ lifetimes int64 // number of bound lifetimes
+ last byte // last byte written to buffer
+}
+
+// fail panics with demangleErr, to be caught in rustToString.
+func (rst *rustState) fail(err string) {
+ panic(demangleErr{err: err, off: rst.off})
+}
+
+// advance advances the current string offset.
+func (rst *rustState) advance(add int) {
+ if len(rst.str) < add {
+ panic("internal error")
+ }
+ rst.str = rst.str[add:]
+ rst.off += add
+}
+
+// checkChar requires that the next character in the string be c,
+// and advances past it.
+func (rst *rustState) checkChar(c byte) {
+ if len(rst.str) == 0 || rst.str[0] != c {
+ rst.fail("expected " + string(c))
+ }
+ rst.advance(1)
+}
+
+// writeByte writes a byte to the buffer.
+func (rst *rustState) writeByte(c byte) {
+ if rst.skip {
+ return
+ }
+ rst.last = c
+ rst.buf.WriteByte(c)
+}
+
+// writeString writes a string to the buffer.
+func (rst *rustState) writeString(s string) {
+ if rst.skip {
+ return
+ }
+ if len(s) > 0 {
+ rst.last = s[len(s)-1]
+ rst.buf.WriteString(s)
+ }
+}
+
+// <symbol-name> = "_R" [<decimal-number>] <path> [<instantiating-crate>]
+// <instantiating-crate> = <path>
+//
+// We've already skipped the "_R".
+func (rst *rustState) symbolName() {
+ if len(rst.str) < 1 {
+ rst.fail("expected symbol-name")
+ }
+
+ if isDigit(rst.str[0]) {
+ rst.fail("unsupported Rust encoding version")
+ }
+
+ rst.path(true)
+
+ if len(rst.str) > 0 {
+ rst.skip = true
+ rst.path(false)
+ }
+}
+
+// <path> = "C" <identifier> // crate root
+// | "M" <impl-path> <type> // <T> (inherent impl)
+// | "X" <impl-path> <type> <path> // <T as Trait> (trait impl)
+// | "Y" <type> <path> // <T as Trait> (trait definition)
+// | "N" <namespace> <path> <identifier> // ...::ident (nested path)
+// | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args)
+// | <backref>
+// <namespace> = "C" // closure
+// | "S" // shim
+// | <A-Z> // other special namespaces
+// | <a-z> // internal namespaces
+//
+// needsSeparator is true if we need to write out :: for a generic;
+// it is passed as false if we are in the middle of a type.
+func (rst *rustState) path(needsSeparator bool) {
+ if len(rst.str) < 1 {
+ rst.fail("expected path")
+ }
+ switch c := rst.str[0]; c {
+ case 'C':
+ rst.advance(1)
+ _, ident := rst.identifier()
+ rst.writeString(ident)
+ case 'M', 'X':
+ rst.advance(1)
+ rst.implPath()
+ rst.writeByte('<')
+ rst.demangleType()
+ if c == 'X' {
+ rst.writeString(" as ")
+ rst.path(false)
+ }
+ rst.writeByte('>')
+ case 'Y':
+ rst.advance(1)
+ rst.writeByte('<')
+ rst.demangleType()
+ rst.writeString(" as ")
+ rst.path(false)
+ rst.writeByte('>')
+ case 'N':
+ rst.advance(1)
+
+ if len(rst.str) < 1 {
+ rst.fail("expected namespace")
+ }
+ ns := rst.str[0]
+ switch {
+ case ns >= 'a' && ns <= 'z':
+ case ns >= 'A' && ns <= 'Z':
+ default:
+ rst.fail("invalid namespace character")
+ }
+ rst.advance(1)
+
+ rst.path(needsSeparator)
+
+ dis, ident := rst.identifier()
+
+ if ns >= 'A' && ns <= 'Z' {
+ rst.writeString("::{")
+ switch ns {
+ case 'C':
+ rst.writeString("closure")
+ case 'S':
+ rst.writeString("shim")
+ default:
+ rst.writeByte(ns)
+ }
+ if len(ident) > 0 {
+ rst.writeByte(':')
+ rst.writeString(ident)
+ }
+ if !rst.skip {
+ fmt.Fprintf(&rst.buf, "#%d}", dis)
+ rst.last = '}'
+ }
+ } else {
+ rst.writeString("::")
+ rst.writeString(ident)
+ }
+ case 'I':
+ rst.advance(1)
+ rst.path(needsSeparator)
+ if needsSeparator {
+ rst.writeString("::")
+ }
+ rst.writeByte('<')
+ first := true
+ for len(rst.str) > 0 && rst.str[0] != 'E' {
+ if first {
+ first = false
+ } else {
+ rst.writeString(", ")
+ }
+ rst.genericArg()
+ }
+ rst.writeByte('>')
+ rst.checkChar('E')
+ case 'B':
+ rst.backref(func() { rst.path(needsSeparator) })
+ default:
+ rst.fail("unrecognized letter in path")
+ }
+}
+
+// <impl-path> = [<disambiguator>] <path>
+func (rst *rustState) implPath() {
+ // This path is not part of the demangled string.
+ hold := rst.skip
+ rst.skip = true
+ defer func() {
+ rst.skip = hold
+ }()
+
+ rst.disambiguator()
+ rst.path(false)
+}
+
+// <identifier> = [<disambiguator>] <undisambiguated-identifier>
+// Returns the disambiguator and the identifier.
+func (rst *rustState) identifier() (int64, string) {
+ dis := rst.disambiguator()
+ ident := rst.undisambiguatedIdentifier()
+ return dis, ident
+}
+
+// <disambiguator> = "s" <base-62-number>
+// This is optional.
+func (rst *rustState) disambiguator() int64 {
+ if len(rst.str) == 0 || rst.str[0] != 's' {
+ return 0
+ }
+ rst.advance(1)
+ return rst.base62Number() + 1
+}
+
+// <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes>
+func (rst *rustState) undisambiguatedIdentifier() string {
+ punycode := false
+ if len(rst.str) > 0 && rst.str[0] == 'u' {
+ rst.advance(1)
+ punycode = true
+ }
+
+ val := rst.decimalNumber()
+
+ if len(rst.str) > 0 && rst.str[0] == '_' {
+ rst.advance(1)
+ }
+
+ if len(rst.str) < val {
+ rst.fail("not enough characters for identifier")
+ }
+ id := rst.str[:val]
+ rst.advance(val)
+
+ for i := 0; i < len(id); i++ {
+ c := id[i]
+ switch {
+ case c >= '0' && c <= '9':
+ case c >= 'A' && c <= 'Z':
+ case c >= 'a' && c <= 'z':
+ case c == '_':
+ default:
+ rst.fail("invalid character in identifier")
+ }
+ }
+
+ if punycode {
+ id = rst.expandPunycode(id)
+ }
+
+ return id
+}
+
+// expandPunycode decodes the Rust version of punycode.
+// This algorithm is taken from RFC 3492 section 6.2.
+func (rst *rustState) expandPunycode(s string) string {
+ const (
+ base = 36
+ tmin = 1
+ tmax = 26
+ skew = 38
+ damp = 700
+ initialBias = 72
+ initialN = 128
+ )
+
+ idx := strings.LastIndex(s, "_")
+ if idx < 0 {
+ rst.fail("missing underscore in punycode string")
+ }
+
+ output := []rune(s[:idx])
+ encoding := s[idx+1:]
+
+ i := 0
+ n := initialN
+ bias := initialBias
+
+ pos := 0
+ for pos < len(encoding) {
+ oldI := i
+ w := 1
+ for k := base; ; k += base {
+ if pos == len(encoding) {
+ rst.fail("unterminated punycode")
+ }
+
+ var digit byte
+ d := encoding[pos]
+ pos++
+ switch {
+ case '0' <= d && d <= '9':
+ digit = d - '0' + 26
+ case 'A' <= d && d <= 'Z':
+ digit = d - 'A'
+ case 'a' <= d && d <= 'z':
+ digit = d - 'a'
+ default:
+ rst.fail("invalid punycode digit")
+ }
+
+ i += int(digit) * w
+ if i < 0 {
+ rst.fail("punycode number overflow")
+ }
+
+ var t int
+ if k <= bias {
+ t = tmin
+ } else if k > bias+tmax {
+ t = tmax
+ } else {
+ t = k - bias
+ }
+
+ if int(digit) < t {
+ break
+ }
+
+ if w >= math.MaxInt32/base {
+ rst.fail("punycode number overflow")
+ }
+ w *= base - t
+ }
+
+ delta := i - oldI
+ numPoints := len(output) + 1
+ firstTime := oldI == 0
+ if firstTime {
+ delta /= damp
+ } else {
+ delta /= 2
+ }
+ delta += delta / numPoints
+ k := 0
+ for delta > ((base-tmin)*tmax)/2 {
+ delta /= base - tmin
+ k += base
+ }
+ bias = k + ((base-tmin+1)*delta)/(delta+skew)
+
+ n += i / (len(output) + 1)
+ if n > utf8.MaxRune {
+ rst.fail("punycode rune overflow")
+ }
+ i %= len(output) + 1
+ output = append(output, 0)
+ copy(output[i+1:], output[i:])
+ output[i] = rune(n)
+ i++
+ }
+
+ return string(output)
+}
+
+// <generic-arg> = <lifetime>
+// | <type>
+// | "K" <const> // forward-compat for const generics
+// <lifetime> = "L" <base-62-number>
+func (rst *rustState) genericArg() {
+ if len(rst.str) < 1 {
+ rst.fail("expected generic-arg")
+ }
+ if rst.str[0] == 'L' {
+ rst.advance(1)
+ rst.writeLifetime(rst.base62Number())
+ } else if rst.str[0] == 'K' {
+ rst.advance(1)
+ rst.demangleConst()
+ } else {
+ rst.demangleType()
+ }
+}
+
+// <binder> = "G" <base-62-number>
+// This is optional.
+func (rst *rustState) binder() {
+ if len(rst.str) < 1 || rst.str[0] != 'G' {
+ return
+ }
+ rst.advance(1)
+
+ binderLifetimes := rst.base62Number() + 1
+
+ // Every bound lifetime should be referenced later.
+ if binderLifetimes >= int64(len(rst.str))-rst.lifetimes {
+ rst.fail("binder lifetimes overflow")
+ }
+
+ rst.writeString("for<")
+ for i := int64(0); i < binderLifetimes; i++ {
+ if i > 0 {
+ rst.writeString(", ")
+ }
+ rst.lifetimes++
+ rst.writeLifetime(1)
+ }
+ rst.writeString("> ")
+}
+
+// <type> = <basic-type>
+// | <path> // named type
+// | "A" <type> <const> // [T; N]
+// | "S" <type> // [T]
+// | "T" {<type>} "E" // (T1, T2, T3, ...)
+// | "R" [<lifetime>] <type> // &T
+// | "Q" [<lifetime>] <type> // &mut T
+// | "P" <type> // *const T
+// | "O" <type> // *mut T
+// | "F" <fn-sig> // fn(...) -> ...
+// | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a
+// | <backref>
+func (rst *rustState) demangleType() {
+ if len(rst.str) < 1 {
+ rst.fail("expected type")
+ }
+ c := rst.str[0]
+ if c >= 'a' && c <= 'z' {
+ rst.basicType()
+ return
+ }
+ switch c {
+ case 'C', 'M', 'X', 'Y', 'N', 'I':
+ rst.path(false)
+ case 'A', 'S':
+ rst.advance(1)
+ rst.writeByte('[')
+ rst.demangleType()
+ if c == 'A' {
+ rst.writeString("; ")
+ rst.demangleConst()
+ }
+ rst.writeByte(']')
+ case 'T':
+ rst.advance(1)
+ rst.writeByte('(')
+ c := 0
+ for len(rst.str) > 0 && rst.str[0] != 'E' {
+ if c > 0 {
+ rst.writeString(", ")
+ }
+ c++
+ rst.demangleType()
+ }
+ if c == 1 {
+ rst.writeByte(',')
+ }
+ rst.writeByte(')')
+ rst.checkChar('E')
+ case 'R', 'Q':
+ rst.advance(1)
+ rst.writeByte('&')
+ if len(rst.str) > 0 && rst.str[0] == 'L' {
+ rst.advance(1)
+ if lifetime := rst.base62Number(); lifetime > 0 {
+ rst.writeLifetime(lifetime)
+ rst.writeByte(' ')
+ }
+ }
+ if c == 'Q' {
+ rst.writeString("mut ")
+ }
+ rst.demangleType()
+ case 'P':
+ rst.advance(1)
+ rst.writeString("*const ")
+ rst.demangleType()
+ case 'O':
+ rst.advance(1)
+ rst.writeString("*mut ")
+ rst.demangleType()
+ case 'F':
+ rst.advance(1)
+ hold := rst.lifetimes
+ rst.fnSig()
+ rst.lifetimes = hold
+ case 'D':
+ rst.advance(1)
+ hold := rst.lifetimes
+ rst.dynBounds()
+ rst.lifetimes = hold
+ if len(rst.str) == 0 || rst.str[0] != 'L' {
+ rst.fail("expected L")
+ }
+ rst.advance(1)
+ if lifetime := rst.base62Number(); lifetime > 0 {
+ if rst.last != ' ' {
+ rst.writeByte(' ')
+ }
+ rst.writeString("+ ")
+ rst.writeLifetime(lifetime)
+ }
+ case 'B':
+ rst.backref(rst.demangleType)
+ default:
+ rst.fail("unrecognized character in type")
+ }
+}
+
+var rustBasicTypes = map[byte]string{
+ 'a': "i8",
+ 'b': "bool",
+ 'c': "char",
+ 'd': "f64",
+ 'e': "str",
+ 'f': "f32",
+ 'h': "u8",
+ 'i': "isize",
+ 'j': "usize",
+ 'l': "i32",
+ 'm': "u32",
+ 'n': "i128",
+ 'o': "u128",
+ 'p': "_",
+ 's': "i16",
+ 't': "u16",
+ 'u': "()",
+ 'v': "...",
+ 'x': "i64",
+ 'y': "u64",
+ 'z': "!",
+}
+
+// <basic-type>
+func (rst *rustState) basicType() {
+ if len(rst.str) < 1 {
+ rst.fail("expected basic type")
+ }
+ str, ok := rustBasicTypes[rst.str[0]]
+ if !ok {
+ rst.fail("unrecognized basic type character")
+ }
+ rst.advance(1)
+ rst.writeString(str)
+}
+
+// <fn-sig> = [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type>
+// <abi> = "C"
+// | <undisambiguated-identifier>
+func (rst *rustState) fnSig() {
+ rst.binder()
+ if len(rst.str) > 0 && rst.str[0] == 'U' {
+ rst.advance(1)
+ rst.writeString("unsafe ")
+ }
+ if len(rst.str) > 0 && rst.str[0] == 'K' {
+ rst.advance(1)
+ if len(rst.str) > 0 && rst.str[0] == 'C' {
+ rst.advance(1)
+ rst.writeString(`extern "C" `)
+ } else {
+ rst.writeString(`extern "`)
+ id := rst.undisambiguatedIdentifier()
+ id = strings.ReplaceAll(id, "_", "-")
+ rst.writeString(id)
+ rst.writeString(`" `)
+ }
+ }
+ rst.writeString("fn(")
+ first := true
+ for len(rst.str) > 0 && rst.str[0] != 'E' {
+ if first {
+ first = false
+ } else {
+ rst.writeString(", ")
+ }
+ rst.demangleType()
+ }
+ rst.checkChar('E')
+ rst.writeByte(')')
+ if len(rst.str) > 0 && rst.str[0] == 'u' {
+ rst.advance(1)
+ } else {
+ rst.writeString(" -> ")
+ rst.demangleType()
+ }
+}
+
+// <dyn-bounds> = [<binder>] {<dyn-trait>} "E"
+func (rst *rustState) dynBounds() {
+ rst.writeString("dyn ")
+ rst.binder()
+ first := true
+ for len(rst.str) > 0 && rst.str[0] != 'E' {
+ if first {
+ first = false
+ } else {
+ rst.writeString(" + ")
+ }
+ rst.dynTrait()
+ }
+ rst.checkChar('E')
+}
+
+// <dyn-trait> = <path> {<dyn-trait-assoc-binding>}
+// <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type>
+func (rst *rustState) dynTrait() {
+ started := rst.pathStartGenerics()
+ for len(rst.str) > 0 && rst.str[0] == 'p' {
+ rst.advance(1)
+ if started {
+ rst.writeString(", ")
+ } else {
+ rst.writeByte('<')
+ started = true
+ }
+ rst.writeString(rst.undisambiguatedIdentifier())
+ rst.writeString(" = ")
+ rst.demangleType()
+ }
+ if started {
+ rst.writeByte('>')
+ }
+}
+
+// pathStartGenerics is like path but if it sees an I to start generic
+// arguments it won't close them. It reports whether it started generics.
+func (rst *rustState) pathStartGenerics() bool {
+ if len(rst.str) < 1 {
+ rst.fail("expected path")
+ }
+ switch rst.str[0] {
+ case 'I':
+ rst.advance(1)
+ rst.path(false)
+ rst.writeByte('<')
+ first := true
+ for len(rst.str) > 0 && rst.str[0] != 'E' {
+ if first {
+ first = false
+ } else {
+ rst.writeString(", ")
+ }
+ rst.genericArg()
+ }
+ rst.checkChar('E')
+ return true
+ case 'B':
+ var started bool
+ rst.backref(func() { started = rst.pathStartGenerics() })
+ return started
+ default:
+ rst.path(false)
+ return false
+ }
+}
+
+// writeLifetime writes out a lifetime binding.
+func (rst *rustState) writeLifetime(lifetime int64) {
+ rst.writeByte('\'')
+ if lifetime == 0 {
+ rst.writeByte('_')
+ return
+ }
+ depth := rst.lifetimes - lifetime
+ if depth < 0 {
+ rst.fail("invalid lifetime")
+ } else if depth < 26 {
+ rst.writeByte('a' + byte(depth))
+ } else {
+ rst.writeByte('z')
+ if !rst.skip {
+ fmt.Fprintf(&rst.buf, "%d", depth-26+1)
+ rst.last = '0'
+ }
+ }
+}
+
+// <const> = <type> <const-data>
+// | "p" // placeholder, shown as _
+// | <backref>
+// <const-data> = ["n"] {<hex-digit>} "_"
+func (rst *rustState) demangleConst() {
+ if len(rst.str) < 1 {
+ rst.fail("expected constant")
+ }
+
+ if rst.str[0] == 'B' {
+ rst.backref(rst.demangleConst)
+ return
+ }
+
+ if rst.str[0] == 'p' {
+ rst.advance(1)
+ rst.writeByte('_')
+ return
+ }
+
+ typ := rst.str[0]
+
+ const (
+ invalid = iota
+ signedInt
+ unsignedInt
+ boolean
+ character
+ )
+
+ var kind int
+ switch typ {
+ case 'a', 's', 'l', 'x', 'n', 'i':
+ kind = signedInt
+ case 'h', 't', 'm', 'y', 'o', 'j':
+ kind = unsignedInt
+ case 'b':
+ kind = boolean
+ case 'c':
+ kind = character
+ default:
+ rst.fail("unrecognized constant type")
+ }
+
+ rst.advance(1)
+
+ if kind == signedInt && len(rst.str) > 0 && rst.str[0] == 'n' {
+ rst.advance(1)
+ rst.writeByte('-')
+ }
+
+ start := rst.str
+ digits := 0
+ val := uint64(0)
+digitLoop:
+ for len(rst.str) > 0 {
+ c := rst.str[0]
+ var digit uint64
+ switch {
+ case c >= '0' && c <= '9':
+ digit = uint64(c - '0')
+ case c >= 'a' && c <= 'f':
+ digit = uint64(c - 'a' + 10)
+ case c == '_':
+ rst.advance(1)
+ break digitLoop
+ default:
+ rst.fail("expected hex digit or _")
+ }
+ rst.advance(1)
+ if val == 0 && digit == 0 && (len(rst.str) == 0 || rst.str[0] != '_') {
+ rst.fail("invalid leading 0 in constant")
+ }
+ val *= 16
+ val += digit
+ digits++
+ }
+
+ if digits == 0 {
+ rst.fail("expected constant")
+ }
+
+ switch kind {
+ case signedInt, unsignedInt:
+ if digits > 16 {
+ // Value too big, just write out the string.
+ rst.writeString("0x")
+ rst.writeString(start[:digits])
+ } else {
+ if !rst.skip {
+ fmt.Fprintf(&rst.buf, "%d", val)
+ rst.last = '0'
+ }
+ }
+ case boolean:
+ if digits > 1 {
+ rst.fail("boolean value too large")
+ } else if val == 0 {
+ rst.writeString("false")
+ } else if val == 1 {
+ rst.writeString("true")
+ } else {
+ rst.fail("invalid boolean value")
+ }
+ case character:
+ if digits > 6 {
+ rst.fail("character value too large")
+ }
+ rst.writeByte('\'')
+ if val == '\t' {
+ rst.writeString(`\t`)
+ } else if val == '\r' {
+ rst.writeString(`\r`)
+ } else if val == '\n' {
+ rst.writeString(`\n`)
+ } else if val == '\\' {
+ rst.writeString(`\\`)
+ } else if val == '\'' {
+ rst.writeString(`\'`)
+ } else if val >= ' ' && val <= '~' {
+ // printable ASCII character
+ rst.writeByte(byte(val))
+ } else {
+ if !rst.skip {
+ fmt.Fprintf(&rst.buf, `\u{%x}`, val)
+ rst.last = '}'
+ }
+ }
+ rst.writeByte('\'')
+ default:
+ panic("internal error")
+ }
+}
+
+// <base-62-number> = {<0-9a-zA-Z>} "_"
+func (rst *rustState) base62Number() int64 {
+ if len(rst.str) > 0 && rst.str[0] == '_' {
+ rst.advance(1)
+ return 0
+ }
+ val := int64(0)
+ for len(rst.str) > 0 {
+ c := rst.str[0]
+ rst.advance(1)
+ if c == '_' {
+ return val + 1
+ }
+ val *= 62
+ if c >= '0' && c <= '9' {
+ val += int64(c - '0')
+ } else if c >= 'a' && c <= 'z' {
+ val += int64(c - 'a' + 10)
+ } else if c >= 'A' && c <= 'Z' {
+ val += int64(c - 'A' + 36)
+ } else {
+ rst.fail("invalid digit in base 62 number")
+ }
+ }
+ rst.fail("expected _ after base 62 number")
+ return 0
+}
+
+// <backref> = "B" <base-62-number>
+func (rst *rustState) backref(demangle func()) {
+ backoff := rst.off
+
+ rst.checkChar('B')
+ idx64 := rst.base62Number()
+
+ if rst.skip {
+ return
+ }
+
+ idx := int(idx64)
+ if int64(idx) != idx64 {
+ rst.fail("backref index overflow")
+ }
+ if idx < 0 || idx >= backoff {
+ rst.fail("invalid backref index")
+ }
+
+ holdStr := rst.str
+ holdOff := rst.off
+ rst.str = rst.orig[idx:backoff]
+ rst.off = idx
+ defer func() {
+ rst.str = holdStr
+ rst.off = holdOff
+ }()
+
+ demangle()
+}
+
+func (rst *rustState) decimalNumber() int {
+ if len(rst.str) == 0 {
+ rst.fail("expected number")
+ }
+
+ val := 0
+ for len(rst.str) > 0 && isDigit(rst.str[0]) {
+ add := int(rst.str[0] - '0')
+ if val >= math.MaxInt32/10-add {
+ rst.fail("decimal number overflow")
+ }
+ val *= 10
+ val += add
+ rst.advance(1)
+ }
+ return val
+}
+
+// oldRustToString demangles a Rust symbol using the old demangling.
+// The second result reports whether this is a valid Rust mangled name.
+func oldRustToString(name string, options []Option) (string, bool) {
+ // We know that the string starts with _ZN.
+ name = name[3:]
+
+ hexDigit := func(c byte) (byte, bool) {
+ switch {
+ case c >= '0' && c <= '9':
+ return c - '0', true
+ case c >= 'a' && c <= 'f':
+ return c - 'a' + 10, true
+ default:
+ return 0, false
+ }
+ }
+
+ // We know that the strings end with "17h" followed by 16 characters
+ // followed by "E". We check that the 16 characters are all hex digits.
+ // Also the hex digits must contain at least 5 distinct digits.
+ seen := uint16(0)
+ for i := len(name) - 17; i < len(name) - 1; i++ {
+ digit, ok := hexDigit(name[i])
+ if !ok {
+ return "", false
+ }
+ seen |= 1 << digit
+ }
+ if bits.OnesCount16(seen) < 5 {
+ return "", false
+ }
+ name = name[:len(name)-20]
+
+ // The name is a sequence of length-preceded identifiers.
+ var sb strings.Builder
+ for len(name) > 0 {
+ if !isDigit(name[0]) {
+ return "", false
+ }
+
+ val := 0
+ for len(name) > 0 && isDigit(name[0]) {
+ add := int(name[0] - '0')
+ if val >= math.MaxInt32/10-add {
+ return "", false
+ }
+ val *= 10
+ val += add
+ name = name[1:]
+ }
+
+ // An optional trailing underscore can separate the
+ // length from the identifier.
+ if len(name) > 0 && name[0] == '_' {
+ name = name[1:]
+ val--
+ }
+
+ if len(name) < val {
+ return "", false
+ }
+
+ id := name[:val]
+ name = name[val:]
+
+ if sb.Len() > 0 {
+ sb.WriteString("::")
+ }
+
+ // Ignore leading underscores preceding escape sequences.
+ if strings.HasPrefix(id, "_$") {
+ id = id[1:]
+ }
+
+ // The identifier can have escape sequences.
+ escape:
+ for len(id) > 0 {
+ switch c := id[0]; c {
+ case '$':
+ codes := map[string]byte {
+ "SP": '@',
+ "BP": '*',
+ "RF": '&',
+ "LT": '<',
+ "GT": '>',
+ "LP": '(',
+ "RP": ')',
+ }
+
+ valid := true
+ if len(id) > 2 && id[1] == 'C' && id[2] == '$' {
+ sb.WriteByte(',')
+ id = id[3:]
+ } else if len(id) > 4 && id[1] == 'u' && id[4] == '$' {
+ dig1, ok1 := hexDigit(id[2])
+ dig2, ok2 := hexDigit(id[3])
+ val := (dig1 << 4) | dig2
+ if !ok1 || !ok2 || dig1 > 7 || val < ' ' {
+ valid = false
+ } else {
+ sb.WriteByte(val)
+ id = id[5:]
+ }
+ } else if len(id) > 3 && id[3] == '$' {
+ if code, ok := codes[id[1:3]]; !ok {
+ valid = false
+ } else {
+ sb.WriteByte(code)
+ id = id[4:]
+ }
+ } else {
+ valid = false
+ }
+ if !valid {
+ sb.WriteString(id)
+ break escape
+ }
+ case '.':
+ if strings.HasPrefix(id, "..") {
+ sb.WriteString("::")
+ id = id[2:]
+ } else {
+ sb.WriteByte(c)
+ id = id[1:]
+ }
+ default:
+ sb.WriteByte(c)
+ id = id[1:]
+ }
+ }
+ }
+
+ return sb.String(), true
+}