aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/ianlancetaylor
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-06-28 09:59:11 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-06-28 09:59:11 +0200
commit7b4e273e539d93682dc87e9a7c7d1f79a4cd1b77 (patch)
treec12ada52827e6b5e8e6620b880a35bb8d2322ebe /vendor/github.com/ianlancetaylor
parentc3e23de010943fd4b18e0dc95ca5b31267fabe6d (diff)
vendor: add github.com/ianlancetaylor/demangle
Add the new package required by pkg/report/fuchsia.go. Also update everything else because there does not seem to be a way to add a package without a wholesale update.
Diffstat (limited to 'vendor/github.com/ianlancetaylor')
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/.gitignore13
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/LICENSE27
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/README.md3
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/ast.go2879
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/c++filt.go144
-rw-r--r--vendor/github.com/ianlancetaylor/demangle/demangle.go2501
6 files changed, 5567 insertions, 0 deletions
diff --git a/vendor/github.com/ianlancetaylor/demangle/.gitignore b/vendor/github.com/ianlancetaylor/demangle/.gitignore
new file mode 100644
index 000000000..4a8b38f46
--- /dev/null
+++ b/vendor/github.com/ianlancetaylor/demangle/.gitignore
@@ -0,0 +1,13 @@
+*.o
+*.a
+*.so
+._*
+.nfs.*
+a.out
+*~
+*.orig
+*.rej
+*.exe
+.*.swp
+core
+demangle.test
diff --git a/vendor/github.com/ianlancetaylor/demangle/LICENSE b/vendor/github.com/ianlancetaylor/demangle/LICENSE
new file mode 100644
index 000000000..d29b37261
--- /dev/null
+++ b/vendor/github.com/ianlancetaylor/demangle/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2015 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/ianlancetaylor/demangle/README.md b/vendor/github.com/ianlancetaylor/demangle/README.md
new file mode 100644
index 000000000..ef3f94a63
--- /dev/null
+++ b/vendor/github.com/ianlancetaylor/demangle/README.md
@@ -0,0 +1,3 @@
+# github.com/ianlancetaylor/demangle
+
+A Go package that can be used to demangle C++ symbol names.
diff --git a/vendor/github.com/ianlancetaylor/demangle/ast.go b/vendor/github.com/ianlancetaylor/demangle/ast.go
new file mode 100644
index 000000000..0ad5354f5
--- /dev/null
+++ b/vendor/github.com/ianlancetaylor/demangle/ast.go
@@ -0,0 +1,2879 @@
+// Copyright 2015 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 (
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+// 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.
+type AST interface {
+ // Internal method to convert to demangled string.
+ print(*printState)
+
+ // Traverse each element of an AST. If the function returns
+ // false, traversal of children of that element is skipped.
+ Traverse(func(AST) bool)
+
+ // Copy an AST with possible transformations.
+ // If the skip function returns true, no copy is required.
+ // If the copy function returns nil, no copy is required.
+ // Otherwise the AST returned by copy is used in a copy of the full AST.
+ // Copy itself returns either a copy or nil.
+ Copy(copy func(AST) AST, skip func(AST) bool) AST
+
+ // Implement the fmt.GoStringer interface.
+ GoString() string
+ goString(indent int, field string) string
+}
+
+// ASTToString returns the demangled name of the AST.
+func ASTToString(a AST, options ...Option) string {
+ tparams := true
+ for _, o := range options {
+ switch o {
+ case NoTemplateParams:
+ tparams = false
+ }
+ }
+
+ ps := printState{tparams: tparams}
+ 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
+
+ buf bytes.Buffer
+ last byte // Last byte written to buffer.
+
+ // The inner field is a list of items to print for a type
+ // name. This is used by types to implement the inside-out
+ // C++ declaration syntax.
+ inner []AST
+
+ // The printing field is a list of items we are currently
+ // printing. This avoids endless recursion if a substitution
+ // reference creates a cycle in the graph.
+ printing []AST
+}
+
+// writeByte adds a byte to the string being printed.
+func (ps *printState) writeByte(b byte) {
+ ps.last = b
+ ps.buf.WriteByte(b)
+}
+
+// writeString adds a string to the string being printed.
+func (ps *printState) writeString(s string) {
+ if len(s) > 0 {
+ ps.last = s[len(s)-1]
+ }
+ ps.buf.WriteString(s)
+}
+
+// Print an AST.
+func (ps *printState) print(a AST) {
+ c := 0
+ for _, v := range ps.printing {
+ if v == a {
+ // We permit the type to appear once, and
+ // return without printing anything if we see
+ // it twice. This is for a case like
+ // _Z6outer2IsEPFilES1_, where the
+ // substitution is printed differently the
+ // second time because the set of inner types
+ // is different.
+ c++
+ if c > 1 {
+ return
+ }
+ }
+ }
+ ps.printing = append(ps.printing, a)
+
+ a.print(ps)
+
+ ps.printing = ps.printing[:len(ps.printing)-1]
+}
+
+// Name is an unqualified name.
+type Name struct {
+ Name string
+}
+
+func (n *Name) print(ps *printState) {
+ ps.writeString(n.Name)
+}
+
+func (n *Name) Traverse(fn func(AST) bool) {
+ fn(n)
+}
+
+func (n *Name) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(n) {
+ return nil
+ }
+ return fn(n)
+}
+
+func (n *Name) GoString() string {
+ return n.goString(0, "Name: ")
+}
+
+func (n *Name) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%s%s", indent, "", field, n.Name)
+}
+
+// Typed is a typed name.
+type Typed struct {
+ Name AST
+ Type AST
+}
+
+func (t *Typed) print(ps *printState) {
+ // We are printing a typed name, so ignore the current set of
+ // inner names to print. Pass down our name as the one to use.
+ holdInner := ps.inner
+ defer func() { ps.inner = holdInner }()
+
+ ps.inner = []AST{t}
+ ps.print(t.Type)
+ if len(ps.inner) > 0 {
+ // The type did not print the name; print it now in
+ // the default location.
+ ps.writeByte(' ')
+ ps.print(t.Name)
+ }
+}
+
+func (t *Typed) printInner(ps *printState) {
+ ps.print(t.Name)
+}
+
+func (t *Typed) Traverse(fn func(AST) bool) {
+ if fn(t) {
+ t.Name.Traverse(fn)
+ t.Type.Traverse(fn)
+ }
+}
+
+func (t *Typed) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(t) {
+ return nil
+ }
+ name := t.Name.Copy(fn, skip)
+ typ := t.Type.Copy(fn, skip)
+ if name == nil && typ == nil {
+ return fn(t)
+ }
+ if name == nil {
+ name = t.Name
+ }
+ if typ == nil {
+ typ = t.Type
+ }
+ t = &Typed{Name: name, Type: typ}
+ if r := fn(t); r != nil {
+ return r
+ }
+ return t
+}
+
+func (t *Typed) GoString() string {
+ return t.goString(0, "")
+}
+
+func (t *Typed) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sTyped:\n%s\n%s", indent, "", field,
+ t.Name.goString(indent+2, "Name: "),
+ t.Type.goString(indent+2, "Type: "))
+}
+
+// Qualified is a name in a scope.
+type Qualified struct {
+ Scope AST
+ Name AST
+
+ // The LocalName field is true if this is parsed as a
+ // <local-name>. We shouldn't really need this, but in some
+ // cases (for the unary sizeof operator) the standard
+ // demangler prints a local name slightly differently. We
+ // keep track of this for compatibility.
+ LocalName bool // A full local name encoding
+}
+
+func (q *Qualified) print(ps *printState) {
+ ps.print(q.Scope)
+ ps.writeString("::")
+ ps.print(q.Name)
+}
+
+func (q *Qualified) Traverse(fn func(AST) bool) {
+ if fn(q) {
+ q.Scope.Traverse(fn)
+ q.Name.Traverse(fn)
+ }
+}
+
+func (q *Qualified) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(q) {
+ return nil
+ }
+ scope := q.Scope.Copy(fn, skip)
+ name := q.Name.Copy(fn, skip)
+ if scope == nil && name == nil {
+ return fn(q)
+ }
+ if scope == nil {
+ scope = q.Scope
+ }
+ if name == nil {
+ name = q.Name
+ }
+ q = &Qualified{Scope: scope, Name: name, LocalName: q.LocalName}
+ if r := fn(q); r != nil {
+ return r
+ }
+ return q
+}
+
+func (q *Qualified) GoString() string {
+ return q.goString(0, "")
+}
+
+func (q *Qualified) goString(indent int, field string) string {
+ s := ""
+ if q.LocalName {
+ s = " LocalName: true"
+ }
+ return fmt.Sprintf("%*s%sQualified:%s\n%s\n%s", indent, "", field,
+ s, q.Scope.goString(indent+2, "Scope: "),
+ q.Name.goString(indent+2, "Name: "))
+}
+
+// Template is a template with arguments.
+type Template struct {
+ Name AST
+ Args []AST
+}
+
+func (t *Template) print(ps *printState) {
+ // Inner types apply to the template as a whole, they don't
+ // cross over into the template.
+ holdInner := ps.inner
+ defer func() { ps.inner = holdInner }()
+
+ ps.inner = nil
+ ps.print(t.Name)
+
+ if !ps.tparams {
+ // Do not print template parameters.
+ return
+ }
+ // We need an extra space after operator<.
+ if ps.last == '<' {
+ ps.writeByte(' ')
+ }
+
+ ps.writeByte('<')
+ first := true
+ for _, a := range t.Args {
+ if ps.isEmpty(a) {
+ continue
+ }
+ if !first {
+ ps.writeString(", ")
+ }
+ ps.print(a)
+ first = false
+ }
+ if ps.last == '>' {
+ // Avoid syntactic ambiguity in old versions of C++.
+ ps.writeByte(' ')
+ }
+ ps.writeByte('>')
+}
+
+func (t *Template) Traverse(fn func(AST) bool) {
+ if fn(t) {
+ t.Name.Traverse(fn)
+ for _, a := range t.Args {
+ a.Traverse(fn)
+ }
+ }
+}
+
+func (t *Template) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(t) {
+ return nil
+ }
+ name := t.Name.Copy(fn, skip)
+ changed := name != nil
+ args := make([]AST, len(t.Args))
+ for i, a := range t.Args {
+ ac := a.Copy(fn, skip)
+ if ac == nil {
+ args[i] = a
+ } else {
+ args[i] = ac
+ changed = true
+ }
+ }
+ if !changed {
+ return fn(t)
+ }
+ if name == nil {
+ name = t.Name
+ }
+ t = &Template{Name: name, Args: args}
+ if r := fn(t); r != nil {
+ return r
+ }
+ return t
+}
+
+func (t *Template) GoString() string {
+ return t.goString(0, "")
+}
+
+func (t *Template) goString(indent int, field string) string {
+ var args string
+ if len(t.Args) == 0 {
+ args = fmt.Sprintf("%*sArgs: nil", indent+2, "")
+ } else {
+ args = fmt.Sprintf("%*sArgs:", indent+2, "")
+ for i, a := range t.Args {
+ args += "\n"
+ args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
+ }
+ }
+ return fmt.Sprintf("%*s%sTemplate (%p):\n%s\n%s", indent, "", field, t,
+ t.Name.goString(indent+2, "Name: "), args)
+}
+
+// TemplateParam is a template parameter. The Template field is
+// filled in while parsing the demangled string. We don't normally
+// see these while printing--they are replaced by the simplify
+// function.
+type TemplateParam struct {
+ Index int
+ Template *Template
+}
+
+func (tp *TemplateParam) print(ps *printState) {
+ if tp.Template == nil {
+ panic("TemplateParam Template field is nil")
+ }
+ if tp.Index >= len(tp.Template.Args) {
+ panic("TemplateParam Index out of bounds")
+ }
+ ps.print(tp.Template.Args[tp.Index])
+}
+
+func (tp *TemplateParam) Traverse(fn func(AST) bool) {
+ fn(tp)
+ // Don't traverse Template--it points elsewhere in the AST.
+}
+
+func (tp *TemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(tp) {
+ return nil
+ }
+ return fn(tp)
+}
+
+func (tp *TemplateParam) GoString() string {
+ return tp.goString(0, "")
+}
+
+func (tp *TemplateParam) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sTemplateParam: Template: %p; Index %d", indent, "", field, tp.Template, tp.Index)
+}
+
+// Qualifiers is an ordered list of type qualifiers.
+type Qualifiers []string
+
+// TypeWithQualifiers is a type with standard qualifiers.
+type TypeWithQualifiers struct {
+ Base AST
+ Qualifiers Qualifiers
+}
+
+func (twq *TypeWithQualifiers) print(ps *printState) {
+ // Give the base type a chance to print the inner types.
+ ps.inner = append(ps.inner, twq)
+ ps.print(twq.Base)
+ if len(ps.inner) > 0 {
+ // The qualifier wasn't printed by Base.
+ ps.writeByte(' ')
+ ps.writeString(strings.Join(twq.Qualifiers, " "))
+ ps.inner = ps.inner[:len(ps.inner)-1]
+ }
+}
+
+// Print qualifiers as an inner type by just printing the qualifiers.
+func (twq *TypeWithQualifiers) printInner(ps *printState) {
+ ps.writeByte(' ')
+ ps.writeString(strings.Join(twq.Qualifiers, " "))
+}
+
+func (twq *TypeWithQualifiers) Traverse(fn func(AST) bool) {
+ if fn(twq) {
+ twq.Base.Traverse(fn)
+ }
+}
+
+func (twq *TypeWithQualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(twq) {
+ return nil
+ }
+ base := twq.Base.Copy(fn, skip)
+ if base == nil {
+ return fn(twq)
+ }
+ twq = &TypeWithQualifiers{Base: base, Qualifiers: twq.Qualifiers}
+ if r := fn(twq); r != nil {
+ return r
+ }
+ return twq
+}
+
+func (twq *TypeWithQualifiers) GoString() string {
+ return twq.goString(0, "")
+}
+
+func (twq *TypeWithQualifiers) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sTypeWithQualifiers: Qualifiers: %s\n%s", indent, "", field,
+ twq.Qualifiers, twq.Base.goString(indent+2, "Base: "))
+}
+
+// MethodWithQualifiers is a method with qualifiers.
+type MethodWithQualifiers struct {
+ Method AST
+ Qualifiers Qualifiers
+ RefQualifier string // "" or "&" or "&&"
+}
+
+func (mwq *MethodWithQualifiers) print(ps *printState) {
+ // Give the base type a chance to print the inner types.
+ ps.inner = append(ps.inner, mwq)
+ ps.print(mwq.Method)
+ if len(ps.inner) > 0 {
+ if len(mwq.Qualifiers) > 0 {
+ ps.writeByte(' ')
+ ps.writeString(strings.Join(mwq.Qualifiers, " "))
+ }
+ if mwq.RefQualifier != "" {
+ ps.writeByte(' ')
+ ps.writeString(mwq.RefQualifier)
+ }
+ ps.inner = ps.inner[:len(ps.inner)-1]
+ }
+}
+
+func (mwq *MethodWithQualifiers) printInner(ps *printState) {
+ if len(mwq.Qualifiers) > 0 {
+ ps.writeByte(' ')
+ ps.writeString(strings.Join(mwq.Qualifiers, " "))
+ }
+ if mwq.RefQualifier != "" {
+ ps.writeByte(' ')
+ ps.writeString(mwq.RefQualifier)
+ }
+}
+
+func (mwq *MethodWithQualifiers) Traverse(fn func(AST) bool) {
+ if fn(mwq) {
+ mwq.Method.Traverse(fn)
+ }
+}
+
+func (mwq *MethodWithQualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(mwq) {
+ return nil
+ }
+ method := mwq.Method.Copy(fn, skip)
+ if method == nil {
+ return fn(mwq)
+ }
+ mwq = &MethodWithQualifiers{Method: method, Qualifiers: mwq.Qualifiers, RefQualifier: mwq.RefQualifier}
+ if r := fn(mwq); r != nil {
+ return r
+ }
+ return mwq
+}
+
+func (mwq *MethodWithQualifiers) GoString() string {
+ return mwq.goString(0, "")
+}
+
+func (mwq *MethodWithQualifiers) goString(indent int, field string) string {
+ var q string
+ if len(mwq.Qualifiers) > 0 {
+ q += fmt.Sprintf(" Qualifiers: %v", mwq.Qualifiers)
+ }
+ if mwq.RefQualifier != "" {
+ if q != "" {
+ q += ";"
+ }
+ q += " RefQualifier: " + mwq.RefQualifier
+ }
+ return fmt.Sprintf("%*s%sMethodWithQualifiers:%s\n%s", indent, "", field,
+ q, mwq.Method.goString(indent+2, "Method: "))
+}
+
+// BuiltinType is a builtin type, like "int".
+type BuiltinType struct {
+ Name string
+}
+
+func (bt *BuiltinType) print(ps *printState) {
+ ps.writeString(bt.Name)
+}
+
+func (bt *BuiltinType) Traverse(fn func(AST) bool) {
+ fn(bt)
+}
+
+func (bt *BuiltinType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(bt) {
+ return nil
+ }
+ return fn(bt)
+}
+
+func (bt *BuiltinType) GoString() string {
+ return bt.goString(0, "")
+}
+
+func (bt *BuiltinType) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sBuiltinType: %s", indent, "", field, bt.Name)
+}
+
+// printBase is common print code for types that are printed with a
+// simple suffix.
+func printBase(ps *printState, qual, base AST) {
+ ps.inner = append(ps.inner, qual)
+ ps.print(base)
+ if len(ps.inner) > 0 {
+ qual.(innerPrinter).printInner(ps)
+ ps.inner = ps.inner[:len(ps.inner)-1]
+ }
+}
+
+// PointerType is a pointer type.
+type PointerType struct {
+ Base AST
+}
+
+func (pt *PointerType) print(ps *printState) {
+ printBase(ps, pt, pt.Base)
+}
+
+func (pt *PointerType) printInner(ps *printState) {
+ ps.writeString("*")
+}
+
+func (pt *PointerType) Traverse(fn func(AST) bool) {
+ if fn(pt) {
+ pt.Base.Traverse(fn)
+ }
+}
+
+func (pt *PointerType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(pt) {
+ return nil
+ }
+ base := pt.Base.Copy(fn, skip)
+ if base == nil {
+ return fn(pt)
+ }
+ pt = &PointerType{Base: base}
+ if r := fn(pt); r != nil {
+ return r
+ }
+ return pt
+}
+
+func (pt *PointerType) GoString() string {
+ return pt.goString(0, "")
+}
+
+func (pt *PointerType) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sPointerType:\n%s", indent, "", field,
+ pt.Base.goString(indent+2, ""))
+}
+
+// ReferenceType is a reference type.
+type ReferenceType struct {
+ Base AST
+}
+
+func (rt *ReferenceType) print(ps *printState) {
+ printBase(ps, rt, rt.Base)
+}
+
+func (rt *ReferenceType) printInner(ps *printState) {
+ ps.writeString("&")
+}
+
+func (rt *ReferenceType) Traverse(fn func(AST) bool) {
+ if fn(rt) {
+ rt.Base.Traverse(fn)
+ }
+}
+
+func (rt *ReferenceType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(rt) {
+ return nil
+ }
+ base := rt.Base.Copy(fn, skip)
+ if base == nil {
+ return fn(rt)
+ }
+ rt = &ReferenceType{Base: base}
+ if r := fn(rt); r != nil {
+ return r
+ }
+ return rt
+}
+
+func (rt *ReferenceType) GoString() string {
+ return rt.goString(0, "")
+}
+
+func (rt *ReferenceType) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sReferenceType:\n%s", indent, "", field,
+ rt.Base.goString(indent+2, ""))
+}
+
+// RvalueReferenceType is an rvalue reference type.
+type RvalueReferenceType struct {
+ Base AST
+}
+
+func (rt *RvalueReferenceType) print(ps *printState) {
+ printBase(ps, rt, rt.Base)
+}
+
+func (rt *RvalueReferenceType) printInner(ps *printState) {
+ ps.writeString("&&")
+}
+
+func (rt *RvalueReferenceType) Traverse(fn func(AST) bool) {
+ if fn(rt) {
+ rt.Base.Traverse(fn)
+ }
+}
+
+func (rt *RvalueReferenceType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(rt) {
+ return nil
+ }
+ base := rt.Base.Copy(fn, skip)
+ if base == nil {
+ return fn(rt)
+ }
+ rt = &RvalueReferenceType{Base: base}
+ if r := fn(rt); r != nil {
+ return r
+ }
+ return rt
+}
+
+func (rt *RvalueReferenceType) GoString() string {
+ return rt.goString(0, "")
+}
+
+func (rt *RvalueReferenceType) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sRvalueReferenceType:\n%s", indent, "", field,
+ rt.Base.goString(indent+2, ""))
+}
+
+// ComplexType is a complex type.
+type ComplexType struct {
+ Base AST
+}
+
+func (ct *ComplexType) print(ps *printState) {
+ printBase(ps, ct, ct.Base)
+}
+
+func (ct *ComplexType) printInner(ps *printState) {
+ ps.writeString(" _Complex")
+}
+
+func (ct *ComplexType) Traverse(fn func(AST) bool) {
+ if fn(ct) {
+ ct.Base.Traverse(fn)
+ }
+}
+
+func (ct *ComplexType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(ct) {
+ return nil
+ }
+ base := ct.Base.Copy(fn, skip)
+ if base == nil {
+ return fn(ct)
+ }
+ ct = &ComplexType{Base: base}
+ if r := fn(ct); r != nil {
+ return r
+ }
+ return ct
+}
+
+func (ct *ComplexType) GoString() string {
+ return ct.goString(0, "")
+}
+
+func (ct *ComplexType) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sComplexType:\n%s", indent, "", field,
+ ct.Base.goString(indent+2, ""))
+}
+
+// ImaginaryType is an imaginary type.
+type ImaginaryType struct {
+ Base AST
+}
+
+func (it *ImaginaryType) print(ps *printState) {
+ printBase(ps, it, it.Base)
+}
+
+func (it *ImaginaryType) printInner(ps *printState) {
+ ps.writeString(" _Imaginary")
+}
+
+func (it *ImaginaryType) Traverse(fn func(AST) bool) {
+ if fn(it) {
+ it.Base.Traverse(fn)
+ }
+}
+
+func (it *ImaginaryType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(it) {
+ return nil
+ }
+ base := it.Base.Copy(fn, skip)
+ if base == nil {
+ return fn(it)
+ }
+ it = &ImaginaryType{Base: base}
+ if r := fn(it); r != nil {
+ return r
+ }
+ return it
+}
+
+func (it *ImaginaryType) GoString() string {
+ return it.goString(0, "")
+}
+
+func (it *ImaginaryType) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sImaginaryType:\n%s", indent, "", field,
+ it.Base.goString(indent+2, ""))
+}
+
+// VendorQualifier is a type qualified by a vendor-specific qualifier.
+type VendorQualifier struct {
+ Qualifier AST
+ Type AST
+}
+
+func (vq *VendorQualifier) print(ps *printState) {
+ ps.inner = append(ps.inner, vq)
+ ps.print(vq.Type)
+ if len(ps.inner) > 0 {
+ ps.printOneInner(nil)
+ }
+}
+
+func (vq *VendorQualifier) printInner(ps *printState) {
+ ps.writeByte(' ')
+ ps.print(vq.Qualifier)
+}
+
+func (vq *VendorQualifier) Traverse(fn func(AST) bool) {
+ if fn(vq) {
+ vq.Qualifier.Traverse(fn)
+ vq.Type.Traverse(fn)
+ }
+}
+
+func (vq *VendorQualifier) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(vq) {
+ return nil
+ }
+ qualifier := vq.Qualifier.Copy(fn, skip)
+ typ := vq.Type.Copy(fn, skip)
+ if qualifier == nil && typ == nil {
+ return fn(vq)
+ }
+ if qualifier == nil {
+ qualifier = vq.Qualifier
+ }
+ if typ == nil {
+ typ = vq.Type
+ }
+ vq = &VendorQualifier{Qualifier: qualifier, Type: vq.Type}
+ if r := fn(vq); r != nil {
+ return r
+ }
+ return vq
+}
+
+func (vq *VendorQualifier) GoString() string {
+ return vq.goString(0, "")
+}
+
+func (vq *VendorQualifier) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sVendorQualifier:\n%s\n%s", indent, "", field,
+ vq.Qualifier.goString(indent+2, "Qualifier: "),
+ vq.Type.goString(indent+2, "Type: "))
+}
+
+// ArrayType is an array type.
+type ArrayType struct {
+ Dimension AST
+ Element AST
+}
+
+func (at *ArrayType) print(ps *printState) {
+ // Pass the array type down as an inner type so that we print
+ // multi-dimensional arrays correctly.
+ ps.inner = append(ps.inner, at)
+ ps.print(at.Element)
+ if ln := len(ps.inner); ln > 0 {
+ ps.inner = ps.inner[:ln-1]
+ at.printDimension(ps)
+ }
+}
+
+func (at *ArrayType) printInner(ps *printState) {
+ at.printDimension(ps)
+}
+
+// Print the array dimension.
+func (at *ArrayType) printDimension(ps *printState) {
+ space := " "
+ for len(ps.inner) > 0 {
+ // We haven't gotten to the real type yet. Use
+ // parentheses around that type, except that if it is
+ // an array type we print it as a multi-dimensional
+ // array
+ in := ps.inner[len(ps.inner)-1]
+ if twq, ok := in.(*TypeWithQualifiers); ok {
+ in = twq.Base
+ }
+ if _, ok := in.(*ArrayType); ok {
+ if in == ps.inner[len(ps.inner)-1] {
+ space = ""
+ }
+ ps.printOneInner(nil)
+ } else {
+ ps.writeString(" (")
+ ps.printInner(false)
+ ps.writeByte(')')
+ }
+ }
+ ps.writeString(space)
+ ps.writeByte('[')
+ ps.print(at.Dimension)
+ ps.writeByte(']')
+}
+
+func (at *ArrayType) Traverse(fn func(AST) bool) {
+ if fn(at) {
+ at.Dimension.Traverse(fn)
+ at.Element.Traverse(fn)
+ }
+}
+
+func (at *ArrayType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(at) {
+ return nil
+ }
+ dimension := at.Dimension.Copy(fn, skip)
+ element := at.Element.Copy(fn, skip)
+ if dimension == nil && element == nil {
+ return fn(at)
+ }
+ if dimension == nil {
+ dimension = at.Dimension
+ }
+ if element == nil {
+ element = at.Element
+ }
+ at = &ArrayType{Dimension: dimension, Element: element}
+ if r := fn(at); r != nil {
+ return r
+ }
+ return at
+}
+
+func (at *ArrayType) GoString() string {
+ return at.goString(0, "")
+}
+
+func (at *ArrayType) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sArrayType:\n%s\n%s", indent, "", field,
+ at.Dimension.goString(indent+2, "Dimension: "),
+ 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.
+type FunctionType struct {
+ Return AST
+ Args []AST
+}
+
+func (ft *FunctionType) print(ps *printState) {
+ if ft.Return != 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)
+ if len(ps.inner) == 0 {
+ // Everything was printed.
+ return
+ }
+ ps.inner = ps.inner[:len(ps.inner)-1]
+ ps.writeByte(' ')
+ }
+ ft.printArgs(ps)
+}
+
+func (ft *FunctionType) printInner(ps *printState) {
+ ft.printArgs(ps)
+}
+
+// printArgs prints the arguments of a function type. It looks at the
+// inner types for spacing.
+func (ft *FunctionType) printArgs(ps *printState) {
+ paren := false
+ space := false
+ for i := len(ps.inner) - 1; i >= 0; i-- {
+ switch ps.inner[i].(type) {
+ case *PointerType, *ReferenceType, *RvalueReferenceType:
+ paren = true
+ case *TypeWithQualifiers, *ComplexType, *ImaginaryType, *PtrMem:
+ space = true
+ paren = true
+ }
+ if paren {
+ break
+ }
+ }
+
+ if paren {
+ if !space && (ps.last != '(' && ps.last != '*') {
+ space = true
+ }
+ if space && ps.last != ' ' {
+ ps.writeByte(' ')
+ }
+ ps.writeByte('(')
+ }
+
+ save := ps.printInner(true)
+
+ if paren {
+ ps.writeByte(')')
+ }
+
+ ps.writeByte('(')
+ first := true
+ for _, a := range ft.Args {
+ if ps.isEmpty(a) {
+ continue
+ }
+ if !first {
+ ps.writeString(", ")
+ }
+ ps.print(a)
+ first = false
+ }
+ ps.writeByte(')')
+
+ ps.inner = save
+ ps.printInner(false)
+}
+
+func (ft *FunctionType) Traverse(fn func(AST) bool) {
+ if fn(ft) {
+ if ft.Return != nil {
+ ft.Return.Traverse(fn)
+ }
+ for _, a := range ft.Args {
+ a.Traverse(fn)
+ }
+ }
+}
+
+func (ft *FunctionType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(ft) {
+ return nil
+ }
+ changed := false
+ var ret AST
+ if ft.Return != nil {
+ ret = ft.Return.Copy(fn, skip)
+ if ret == nil {
+ ret = ft.Return
+ } else {
+ changed = true
+ }
+ }
+ args := make([]AST, len(ft.Args))
+ for i, a := range ft.Args {
+ ac := a.Copy(fn, skip)
+ if ac == nil {
+ args[i] = a
+ } else {
+ args[i] = ac
+ changed = true
+ }
+ }
+ if !changed {
+ return fn(ft)
+ }
+ ft = &FunctionType{Return: ret, Args: args}
+ if r := fn(ft); r != nil {
+ return r
+ }
+ return ft
+}
+
+func (ft *FunctionType) GoString() string {
+ return ft.goString(0, "")
+}
+
+func (ft *FunctionType) goString(indent int, field string) string {
+ var r string
+ if ft.Return == nil {
+ r = fmt.Sprintf("%*sReturn: nil", indent+2, "")
+ } else {
+ r = ft.Return.goString(indent+2, "Return: ")
+ }
+ var args string
+ if len(ft.Args) == 0 {
+ args = fmt.Sprintf("%*sArgs: nil", indent+2, "")
+ } else {
+ args = fmt.Sprintf("%*sArgs:", indent+2, "")
+ for i, a := range ft.Args {
+ args += "\n"
+ args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
+ }
+ }
+ return fmt.Sprintf("%*s%sFunctionType:\n%s\n%s", indent, "", field, r, args)
+}
+
+// FunctionParam is a parameter of a function, used for last-specified
+// return type in a closure.
+type FunctionParam struct {
+ Index int
+}
+
+func (fp *FunctionParam) print(ps *printState) {
+ if fp.Index == 0 {
+ ps.writeString("this")
+ } else {
+ fmt.Fprintf(&ps.buf, "{parm#%d}", fp.Index)
+ }
+}
+
+func (fp *FunctionParam) Traverse(fn func(AST) bool) {
+ fn(fp)
+}
+
+func (fp *FunctionParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(fp) {
+ return nil
+ }
+ return fn(fp)
+}
+
+func (fp *FunctionParam) GoString() string {
+ return fp.goString(0, "")
+}
+
+func (fp *FunctionParam) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sFunctionParam: %d", indent, "", field, fp.Index)
+}
+
+// PtrMem is a pointer-to-member expression.
+type PtrMem struct {
+ Class AST
+ Member AST
+}
+
+func (pm *PtrMem) print(ps *printState) {
+ ps.inner = append(ps.inner, pm)
+ ps.print(pm.Member)
+ if len(ps.inner) > 0 {
+ ps.printOneInner(nil)
+ }
+}
+
+func (pm *PtrMem) printInner(ps *printState) {
+ if ps.last != '(' {
+ ps.writeByte(' ')
+ }
+ ps.print(pm.Class)
+ ps.writeString("::*")
+}
+
+func (pm *PtrMem) Traverse(fn func(AST) bool) {
+ if fn(pm) {
+ pm.Class.Traverse(fn)
+ pm.Member.Traverse(fn)
+ }
+}
+
+func (pm *PtrMem) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(pm) {
+ return nil
+ }
+ class := pm.Class.Copy(fn, skip)
+ member := pm.Member.Copy(fn, skip)
+ if class == nil && member == nil {
+ return fn(pm)
+ }
+ if class == nil {
+ class = pm.Class
+ }
+ if member == nil {
+ member = pm.Member
+ }
+ pm = &PtrMem{Class: class, Member: member}
+ if r := fn(pm); r != nil {
+ return r
+ }
+ return pm
+}
+
+func (pm *PtrMem) GoString() string {
+ return pm.goString(0, "")
+}
+
+func (pm *PtrMem) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sPtrMem:\n%s\n%s", indent, "", field,
+ pm.Class.goString(indent+2, "Class: "),
+ pm.Member.goString(indent+2, "Member: "))
+}
+
+// FixedType is a fixed numeric type of unknown size.
+type FixedType struct {
+ Base AST
+ Accum bool
+ Sat bool
+}
+
+func (ft *FixedType) print(ps *printState) {
+ if ft.Sat {
+ ps.writeString("_Sat ")
+ }
+ if bt, ok := ft.Base.(*BuiltinType); ok && bt.Name == "int" {
+ // The standard demangler skips printing "int".
+ } else {
+ ps.print(ft.Base)
+ ps.writeByte(' ')
+ }
+ if ft.Accum {
+ ps.writeString("_Accum")
+ } else {
+ ps.writeString("_Fract")
+ }
+}
+
+func (ft *FixedType) Traverse(fn func(AST) bool) {
+ if fn(ft) {
+ ft.Base.Traverse(fn)
+ }
+}
+
+func (ft *FixedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(ft) {
+ return nil
+ }
+ base := ft.Base.Copy(fn, skip)
+ if base == nil {
+ return fn(ft)
+ }
+ ft = &FixedType{Base: base, Accum: ft.Accum, Sat: ft.Sat}
+ if r := fn(ft); r != nil {
+ return r
+ }
+ return ft
+}
+
+func (ft *FixedType) GoString() string {
+ return ft.goString(0, "")
+}
+
+func (ft *FixedType) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sFixedType: Accum: %t; Sat: %t\n%s", indent, "", field,
+ ft.Accum, ft.Sat,
+ ft.Base.goString(indent+2, "Base: "))
+}
+
+// VectorType is a vector type.
+type VectorType struct {
+ Dimension AST
+ Base AST
+}
+
+func (vt *VectorType) print(ps *printState) {
+ ps.inner = append(ps.inner, vt)
+ ps.print(vt.Base)
+ if len(ps.inner) > 0 {
+ ps.printOneInner(nil)
+ }
+}
+
+func (vt *VectorType) printInner(ps *printState) {
+ ps.writeString(" __vector(")
+ ps.print(vt.Dimension)
+ ps.writeByte(')')
+}
+
+func (vt *VectorType) Traverse(fn func(AST) bool) {
+ if fn(vt) {
+ vt.Dimension.Traverse(fn)
+ vt.Base.Traverse(fn)
+ }
+}
+
+func (vt *VectorType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(vt) {
+ return nil
+ }
+ dimension := vt.Dimension.Copy(fn, skip)
+ base := vt.Base.Copy(fn, skip)
+ if dimension == nil && base == nil {
+ return fn(vt)
+ }
+ if dimension == nil {
+ dimension = vt.Dimension
+ }
+ if base == nil {
+ base = vt.Base
+ }
+ vt = &VectorType{Dimension: dimension, Base: base}
+ if r := fn(vt); r != nil {
+ return r
+ }
+ return vt
+}
+
+func (vt *VectorType) GoString() string {
+ return vt.goString(0, "")
+}
+
+func (vt *VectorType) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sVectorType:\n%s\n%s", indent, "", field,
+ vt.Dimension.goString(indent+2, "Dimension: "),
+ vt.Base.goString(indent+2, "Base: "))
+}
+
+// Decltype is the decltype operator.
+type Decltype struct {
+ Expr AST
+}
+
+func (dt *Decltype) print(ps *printState) {
+ ps.writeString("decltype (")
+ ps.print(dt.Expr)
+ ps.writeByte(')')
+}
+
+func (dt *Decltype) Traverse(fn func(AST) bool) {
+ if fn(dt) {
+ dt.Expr.Traverse(fn)
+ }
+}
+
+func (dt *Decltype) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(dt) {
+ return nil
+ }
+ expr := dt.Expr.Copy(fn, skip)
+ if expr == nil {
+ return fn(dt)
+ }
+ dt = &Decltype{Expr: expr}
+ if r := fn(dt); r != nil {
+ return r
+ }
+ return dt
+}
+
+func (dt *Decltype) GoString() string {
+ return dt.goString(0, "")
+}
+
+func (dt *Decltype) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sDecltype:\n%s", indent, "", field,
+ dt.Expr.goString(indent+2, "Expr: "))
+}
+
+// Operator is an operator.
+type Operator struct {
+ Name string
+}
+
+func (op *Operator) print(ps *printState) {
+ ps.writeString("operator")
+ if isLower(op.Name[0]) {
+ ps.writeByte(' ')
+ }
+ n := op.Name
+ n = strings.TrimSuffix(n, " ")
+ ps.writeString(n)
+}
+
+func (op *Operator) Traverse(fn func(AST) bool) {
+ fn(op)
+}
+
+func (op *Operator) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(op) {
+ return nil
+ }
+ return fn(op)
+}
+
+func (op *Operator) GoString() string {
+ return op.goString(0, "")
+}
+
+func (op *Operator) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sOperator: %s", indent, "", field, op.Name)
+}
+
+// Constructor is a constructor.
+type Constructor struct {
+ Name AST
+}
+
+func (c *Constructor) print(ps *printState) {
+ ps.print(c.Name)
+}
+
+func (c *Constructor) Traverse(fn func(AST) bool) {
+ if fn(c) {
+ c.Name.Traverse(fn)
+ }
+}
+
+func (c *Constructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(c) {
+ return nil
+ }
+ name := c.Name.Copy(fn, skip)
+ if name == nil {
+ return fn(c)
+ }
+ c = &Constructor{Name: name}
+ if r := fn(c); r != nil {
+ return r
+ }
+ return c
+}
+
+func (c *Constructor) GoString() string {
+ return c.goString(0, "")
+}
+
+func (c *Constructor) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sConstructor:\n%s", indent, "", field, c.Name.goString(indent+2, "Name: "))
+}
+
+// Destructor is a destructor.
+type Destructor struct {
+ Name AST
+}
+
+func (d *Destructor) print(ps *printState) {
+ ps.writeByte('~')
+ ps.print(d.Name)
+}
+
+func (d *Destructor) Traverse(fn func(AST) bool) {
+ if fn(d) {
+ d.Name.Traverse(fn)
+ }
+}
+
+func (d *Destructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(d) {
+ return nil
+ }
+ name := d.Name.Copy(fn, skip)
+ if name == nil {
+ return fn(d)
+ }
+ d = &Destructor{Name: name}
+ if r := fn(d); r != nil {
+ return r
+ }
+ return d
+}
+
+func (d *Destructor) GoString() string {
+ return d.goString(0, "")
+}
+
+func (d *Destructor) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sDestructor:\n%s", indent, "", field, d.Name.goString(indent+2, "Name: "))
+}
+
+// GlobalCDtor is a global constructor or destructor.
+type GlobalCDtor struct {
+ Ctor bool
+ Key AST
+}
+
+func (gcd *GlobalCDtor) print(ps *printState) {
+ ps.writeString("global ")
+ if gcd.Ctor {
+ ps.writeString("constructors")
+ } else {
+ ps.writeString("destructors")
+ }
+ ps.writeString(" keyed to ")
+ ps.print(gcd.Key)
+}
+
+func (gcd *GlobalCDtor) Traverse(fn func(AST) bool) {
+ if fn(gcd) {
+ gcd.Key.Traverse(fn)
+ }
+}
+
+func (gcd *GlobalCDtor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(gcd) {
+ return nil
+ }
+ key := gcd.Key.Copy(fn, skip)
+ if key == nil {
+ return fn(gcd)
+ }
+ gcd = &GlobalCDtor{Ctor: gcd.Ctor, Key: key}
+ if r := fn(gcd); r != nil {
+ return r
+ }
+ return gcd
+}
+
+func (gcd *GlobalCDtor) GoString() string {
+ return gcd.goString(0, "")
+}
+
+func (gcd *GlobalCDtor) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sGlobalCDtor: Ctor: %t\n%s", indent, "", field,
+ gcd.Ctor, gcd.Key.goString(indent+2, "Key: "))
+}
+
+// TaggedName is a name with an ABI tag.
+type TaggedName struct {
+ Name AST
+ Tag AST
+}
+
+func (t *TaggedName) print(ps *printState) {
+ ps.print(t.Name)
+ ps.writeString("[abi:")
+ ps.print(t.Tag)
+ ps.writeByte(']')
+}
+
+func (t *TaggedName) Traverse(fn func(AST) bool) {
+ if fn(t) {
+ t.Name.Traverse(fn)
+ t.Tag.Traverse(fn)
+ }
+}
+
+func (t *TaggedName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(t) {
+ return nil
+ }
+ name := t.Name.Copy(fn, skip)
+ tag := t.Tag.Copy(fn, skip)
+ if name == nil && tag == nil {
+ return fn(t)
+ }
+ if name == nil {
+ name = t.Name
+ }
+ if tag == nil {
+ tag = t.Tag
+ }
+ t = &TaggedName{Name: name, Tag: tag}
+ if r := fn(t); r != nil {
+ return r
+ }
+ return t
+}
+
+func (t *TaggedName) GoString() string {
+ return t.goString(0, "")
+}
+
+func (t *TaggedName) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sTaggedName:\n%s\n%s", indent, "", field,
+ t.Name.goString(indent+2, "Name: "),
+ t.Tag.goString(indent+2, "Tag: "))
+}
+
+// PackExpansion is a pack expansion. The Pack field may be nil.
+type PackExpansion struct {
+ Base AST
+ Pack *ArgumentPack
+}
+
+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("...")
+ } else {
+ ps.print(pe.Base)
+ }
+}
+
+func (pe *PackExpansion) Traverse(fn func(AST) bool) {
+ if fn(pe) {
+ pe.Base.Traverse(fn)
+ // Don't traverse Template--it points elsewhere in the AST.
+ }
+}
+
+func (pe *PackExpansion) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(pe) {
+ return nil
+ }
+ base := pe.Base.Copy(fn, skip)
+ if base == nil {
+ return fn(pe)
+ }
+ pe = &PackExpansion{Base: base, Pack: pe.Pack}
+ if r := fn(pe); r != nil {
+ return r
+ }
+ return pe
+}
+
+func (pe *PackExpansion) GoString() string {
+ return pe.goString(0, "")
+}
+
+func (pe *PackExpansion) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sPackExpansion: Pack: %p\n%s", indent, "", field,
+ pe.Pack, pe.Base.goString(indent+2, "Base: "))
+}
+
+// ArgumentPack is an argument pack.
+type ArgumentPack struct {
+ Args []AST
+}
+
+func (ap *ArgumentPack) print(ps *printState) {
+ for i, a := range ap.Args {
+ if i > 0 {
+ ps.writeString(", ")
+ }
+ ps.print(a)
+ }
+}
+
+func (ap *ArgumentPack) Traverse(fn func(AST) bool) {
+ if fn(ap) {
+ for _, a := range ap.Args {
+ a.Traverse(fn)
+ }
+ }
+}
+
+func (ap *ArgumentPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(ap) {
+ return nil
+ }
+ args := make([]AST, len(ap.Args))
+ changed := false
+ for i, a := range ap.Args {
+ ac := a.Copy(fn, skip)
+ if ac == nil {
+ args[i] = a
+ } else {
+ args[i] = ac
+ changed = true
+ }
+ }
+ if !changed {
+ return fn(ap)
+ }
+ ap = &ArgumentPack{Args: args}
+ if r := fn(ap); r != nil {
+ return r
+ }
+ return ap
+}
+
+func (ap *ArgumentPack) GoString() string {
+ return ap.goString(0, "")
+}
+
+func (ap *ArgumentPack) goString(indent int, field string) string {
+ if len(ap.Args) == 0 {
+ return fmt.Sprintf("%*s%sArgumentPack: nil", indent, "", field)
+ }
+ s := fmt.Sprintf("%*s%sArgumentPack:", indent, "", field)
+ for i, a := range ap.Args {
+ s += "\n"
+ s += a.goString(indent+2, fmt.Sprintf("%d: ", i))
+ }
+ return s
+}
+
+// SizeofPack is the sizeof operator applied to an argument pack.
+type SizeofPack struct {
+ Pack *ArgumentPack
+}
+
+func (sp *SizeofPack) print(ps *printState) {
+ ps.writeString(fmt.Sprintf("%d", len(sp.Pack.Args)))
+}
+
+func (sp *SizeofPack) Traverse(fn func(AST) bool) {
+ fn(sp)
+ // Don't traverse the pack--it points elsewhere in the AST.
+}
+
+func (sp *SizeofPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(sp) {
+ return nil
+ }
+ sp = &SizeofPack{Pack: sp.Pack}
+ if r := fn(sp); r != nil {
+ return r
+ }
+ return sp
+}
+
+func (sp *SizeofPack) GoString() string {
+ return sp.goString(0, "")
+}
+
+func (sp *SizeofPack) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sSizeofPack: Pack: %p", indent, "", field, sp.Pack)
+}
+
+// SizeofArgs is the size of a captured template parameter pack from
+// an alias template.
+type SizeofArgs struct {
+ Args []AST
+}
+
+func (sa *SizeofArgs) print(ps *printState) {
+ c := 0
+ for _, a := range sa.Args {
+ if ap, ok := a.(*ArgumentPack); ok {
+ c += len(ap.Args)
+ } else if el, ok := a.(*ExprList); ok {
+ c += len(el.Exprs)
+ } else {
+ c++
+ }
+ }
+ ps.writeString(fmt.Sprintf("%d", c))
+}
+
+func (sa *SizeofArgs) Traverse(fn func(AST) bool) {
+ if fn(sa) {
+ for _, a := range sa.Args {
+ a.Traverse(fn)
+ }
+ }
+}
+
+func (sa *SizeofArgs) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(sa) {
+ return nil
+ }
+ changed := false
+ args := make([]AST, len(sa.Args))
+ for i, a := range sa.Args {
+ ac := a.Copy(fn, skip)
+ if ac == nil {
+ args[i] = a
+ } else {
+ args[i] = ac
+ changed = true
+ }
+ }
+ if !changed {
+ return fn(sa)
+ }
+ sa = &SizeofArgs{Args: args}
+ if r := fn(sa); r != nil {
+ return r
+ }
+ return sa
+}
+
+func (sa *SizeofArgs) GoString() string {
+ return sa.goString(0, "")
+}
+
+func (sa *SizeofArgs) goString(indent int, field string) string {
+ var args string
+ if len(sa.Args) == 0 {
+ args = fmt.Sprintf("%*sArgs: nil", indent+2, "")
+ } else {
+ args = fmt.Sprintf("%*sArgs:", indent+2, "")
+ for i, a := range sa.Args {
+ args += "\n"
+ args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
+ }
+ }
+ return fmt.Sprintf("%*s%sSizeofArgs:\n%s", indent, "", field, args)
+}
+
+// Cast is a type cast.
+type Cast struct {
+ To AST
+}
+
+func (c *Cast) print(ps *printState) {
+ ps.writeString("operator ")
+ ps.print(c.To)
+}
+
+func (c *Cast) Traverse(fn func(AST) bool) {
+ if fn(c) {
+ c.To.Traverse(fn)
+ }
+}
+
+func (c *Cast) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(c) {
+ return nil
+ }
+ to := c.To.Copy(fn, skip)
+ if to == nil {
+ return fn(c)
+ }
+ c = &Cast{To: to}
+ if r := fn(c); r != nil {
+ return r
+ }
+ return c
+}
+
+func (c *Cast) GoString() string {
+ return c.goString(0, "")
+}
+
+func (c *Cast) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sCast\n%s", indent, "", field,
+ c.To.goString(indent+2, "To: "))
+}
+
+// The parenthesize function prints the string for val, wrapped in
+// parentheses if necessary.
+func parenthesize(ps *printState, val AST) {
+ paren := false
+ switch v := val.(type) {
+ case *Name, *InitializerList, *FunctionParam:
+ case *Qualified:
+ if v.LocalName {
+ paren = true
+ }
+ default:
+ paren = true
+ }
+ if paren {
+ ps.writeByte('(')
+ }
+ ps.print(val)
+ if paren {
+ ps.writeByte(')')
+ }
+}
+
+// Nullary is an operator in an expression with no arguments, such as
+// throw.
+type Nullary struct {
+ Op AST
+}
+
+func (n *Nullary) print(ps *printState) {
+ if op, ok := n.Op.(*Operator); ok {
+ ps.writeString(op.Name)
+ } else {
+ ps.print(n.Op)
+ }
+}
+
+func (n *Nullary) Traverse(fn func(AST) bool) {
+ if fn(n) {
+ n.Op.Traverse(fn)
+ }
+}
+
+func (n *Nullary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(n) {
+ return nil
+ }
+ op := n.Op.Copy(fn, skip)
+ if op == nil {
+ return fn(n)
+ }
+ n = &Nullary{Op: op}
+ if r := fn(n); r != nil {
+ return r
+ }
+ return n
+}
+
+func (n *Nullary) GoString() string {
+ return n.goString(0, "")
+}
+
+func (n *Nullary) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sNullary:\n%s", indent, "", field,
+ n.Op.goString(indent+2, "Op: "))
+}
+
+// Unary is a unary operation in an expression.
+type Unary struct {
+ Op AST
+ Expr AST
+ Suffix bool // true for ++ -- when used as postfix
+ SizeofType bool // true for sizeof (type)
+}
+
+func (u *Unary) print(ps *printState) {
+ 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 u.Suffix {
+ parenthesize(ps, expr)
+ }
+
+ if op, ok := u.Op.(*Operator); ok {
+ ps.writeString(op.Name)
+ } else if c, ok := u.Op.(*Cast); ok {
+ ps.writeByte('(')
+ ps.print(c.To)
+ ps.writeByte(')')
+ } else {
+ ps.print(u.Op)
+ }
+
+ if !u.Suffix {
+ if op, ok := u.Op.(*Operator); ok && op.Name == "::" {
+ // Don't use parentheses after ::.
+ ps.print(expr)
+ } else if u.SizeofType {
+ // Always use parentheses for sizeof argument.
+ ps.writeByte('(')
+ ps.print(expr)
+ ps.writeByte(')')
+ } else {
+ parenthesize(ps, expr)
+ }
+ }
+}
+
+func (u *Unary) Traverse(fn func(AST) bool) {
+ if fn(u) {
+ u.Op.Traverse(fn)
+ u.Expr.Traverse(fn)
+ }
+}
+
+func (u *Unary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(u) {
+ return nil
+ }
+ op := u.Op.Copy(fn, skip)
+ expr := u.Expr.Copy(fn, skip)
+ if op == nil && expr == nil {
+ return fn(u)
+ }
+ if op == nil {
+ op = u.Op
+ }
+ if expr == nil {
+ expr = u.Expr
+ }
+ u = &Unary{Op: op, Expr: expr, Suffix: u.Suffix, SizeofType: u.SizeofType}
+ if r := fn(u); r != nil {
+ return r
+ }
+ return u
+}
+
+func (u *Unary) GoString() string {
+ return u.goString(0, "")
+}
+
+func (u *Unary) goString(indent int, field string) string {
+ var s string
+ if u.Suffix {
+ s = " Suffix: true"
+ }
+ if u.SizeofType {
+ s += " SizeofType: true"
+ }
+ return fmt.Sprintf("%*s%sUnary:%s\n%s\n%s", indent, "", field,
+ s, u.Op.goString(indent+2, "Op: "),
+ u.Expr.goString(indent+2, "Expr: "))
+}
+
+// Binary is a binary operation in an expression.
+type Binary struct {
+ Op AST
+ Left AST
+ Right AST
+}
+
+func (b *Binary) print(ps *printState) {
+ op, _ := b.Op.(*Operator)
+
+ if op != nil && strings.Contains(op.Name, "cast") {
+ ps.writeString(op.Name)
+ ps.writeByte('<')
+ ps.print(b.Left)
+ ps.writeString(">(")
+ ps.print(b.Right)
+ ps.writeByte(')')
+ return
+ }
+
+ // Use an extra set of parentheses around an expression that
+ // uses the greater-than operator, so that it does not get
+ // confused with the '>' that ends template parameters.
+ if op != nil && op.Name == ">" {
+ ps.writeByte('(')
+ }
+
+ left := b.Left
+
+ // A function call in an expression should not print the types
+ // of the arguments.
+ if op != nil && op.Name == "()" {
+ if ty, ok := b.Left.(*Typed); ok {
+ left = ty.Name
+ }
+ }
+
+ parenthesize(ps, left)
+
+ if op != nil && op.Name == "[]" {
+ ps.writeByte('[')
+ ps.print(b.Right)
+ ps.writeByte(']')
+ return
+ }
+
+ if op != nil {
+ if op.Name != "()" {
+ ps.writeString(op.Name)
+ }
+ } else {
+ ps.print(b.Op)
+ }
+
+ parenthesize(ps, b.Right)
+
+ if op != nil && op.Name == ">" {
+ ps.writeByte(')')
+ }
+}
+
+func (b *Binary) Traverse(fn func(AST) bool) {
+ if fn(b) {
+ b.Op.Traverse(fn)
+ b.Left.Traverse(fn)
+ b.Right.Traverse(fn)
+ }
+}
+
+func (b *Binary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(b) {
+ return nil
+ }
+ op := b.Op.Copy(fn, skip)
+ left := b.Left.Copy(fn, skip)
+ right := b.Right.Copy(fn, skip)
+ if op == nil && left == nil && right == nil {
+ return fn(b)
+ }
+ if op == nil {
+ op = b.Op
+ }
+ if left == nil {
+ left = b.Left
+ }
+ if right == nil {
+ right = b.Right
+ }
+ b = &Binary{Op: op, Left: left, Right: right}
+ if r := fn(b); r != nil {
+ return r
+ }
+ return b
+}
+
+func (b *Binary) GoString() string {
+ return b.goString(0, "")
+}
+
+func (b *Binary) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sBinary:\n%s\n%s\n%s", indent, "", field,
+ b.Op.goString(indent+2, "Op: "),
+ b.Left.goString(indent+2, "Left: "),
+ b.Right.goString(indent+2, "Right: "))
+}
+
+// Trinary is the ?: trinary operation in an expression.
+type Trinary struct {
+ Op AST
+ First AST
+ Second AST
+ Third AST
+}
+
+func (t *Trinary) print(ps *printState) {
+ parenthesize(ps, t.First)
+ ps.writeByte('?')
+ parenthesize(ps, t.Second)
+ ps.writeString(" : ")
+ parenthesize(ps, t.Third)
+}
+
+func (t *Trinary) Traverse(fn func(AST) bool) {
+ if fn(t) {
+ t.Op.Traverse(fn)
+ t.First.Traverse(fn)
+ t.Second.Traverse(fn)
+ t.Third.Traverse(fn)
+ }
+}
+
+func (t *Trinary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(t) {
+ return nil
+ }
+ op := t.Op.Copy(fn, skip)
+ first := t.First.Copy(fn, skip)
+ second := t.Second.Copy(fn, skip)
+ third := t.Third.Copy(fn, skip)
+ if op == nil && first == nil && second == nil && third == nil {
+ return fn(t)
+ }
+ if op == nil {
+ op = t.Op
+ }
+ if first == nil {
+ first = t.First
+ }
+ if second == nil {
+ second = t.Second
+ }
+ if third == nil {
+ third = t.Third
+ }
+ t = &Trinary{Op: op, First: first, Second: second, Third: third}
+ if r := fn(t); r != nil {
+ return r
+ }
+ return t
+}
+
+func (t *Trinary) GoString() string {
+ return t.goString(0, "")
+}
+
+func (t *Trinary) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sTrinary:\n%s\n%s\n%s\n%s", indent, "", field,
+ t.Op.goString(indent+2, "Op: "),
+ t.First.goString(indent+2, "First: "),
+ t.Second.goString(indent+2, "Second: "),
+ t.Third.goString(indent+2, "Third: "))
+}
+
+// Fold is a C++17 fold-expression. Arg2 is nil for a unary operator.
+type Fold struct {
+ Left bool
+ Op AST
+ Arg1 AST
+ Arg2 AST
+}
+
+func (f *Fold) print(ps *printState) {
+ op, _ := f.Op.(*Operator)
+ printOp := func() {
+ if op != nil {
+ ps.writeString(op.Name)
+ } else {
+ ps.print(f.Op)
+ }
+ }
+
+ if f.Arg2 == nil {
+ if f.Left {
+ ps.writeString("(...")
+ printOp()
+ parenthesize(ps, f.Arg1)
+ ps.writeString(")")
+ } else {
+ ps.writeString("(")
+ parenthesize(ps, f.Arg1)
+ printOp()
+ ps.writeString("...)")
+ }
+ } else {
+ ps.writeString("(")
+ parenthesize(ps, f.Arg1)
+ printOp()
+ ps.writeString("...")
+ printOp()
+ parenthesize(ps, f.Arg2)
+ ps.writeString(")")
+ }
+}
+
+func (f *Fold) Traverse(fn func(AST) bool) {
+ if fn(f) {
+ f.Op.Traverse(fn)
+ f.Arg1.Traverse(fn)
+ if f.Arg2 != nil {
+ f.Arg2.Traverse(fn)
+ }
+ }
+}
+
+func (f *Fold) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(f) {
+ return nil
+ }
+ op := f.Op.Copy(fn, skip)
+ arg1 := f.Arg1.Copy(fn, skip)
+ var arg2 AST
+ if f.Arg2 != nil {
+ arg2 = f.Arg2.Copy(fn, skip)
+ }
+ if op == nil && arg1 == nil && arg2 == nil {
+ return fn(f)
+ }
+ if op == nil {
+ op = f.Op
+ }
+ if arg1 == nil {
+ arg1 = f.Arg1
+ }
+ if arg2 == nil {
+ arg2 = f.Arg2
+ }
+ f = &Fold{Left: f.Left, Op: op, Arg1: arg1, Arg2: arg2}
+ if r := fn(f); r != nil {
+ return r
+ }
+ return f
+}
+
+func (f *Fold) GoString() string {
+ return f.goString(0, "")
+}
+
+func (f *Fold) goString(indent int, field string) string {
+ if f.Arg2 == nil {
+ return fmt.Sprintf("%*s%sFold: Left: %t\n%s\n%s", indent, "", field,
+ f.Left, f.Op.goString(indent+2, "Op: "),
+ f.Arg1.goString(indent+2, "Arg1: "))
+ } else {
+ return fmt.Sprintf("%*s%sFold: Left: %t\n%s\n%s\n%s", indent, "", field,
+ f.Left, f.Op.goString(indent+2, "Op: "),
+ f.Arg1.goString(indent+2, "Arg1: "),
+ f.Arg2.goString(indent+2, "Arg2: "))
+ }
+}
+
+// New is a use of operator new in an expression.
+type New struct {
+ Op AST
+ Place AST
+ Type AST
+ Init AST
+}
+
+func (n *New) print(ps *printState) {
+ // Op doesn't really matter for printing--we always print "new".
+ ps.writeString("new ")
+ if n.Place != nil {
+ parenthesize(ps, n.Place)
+ ps.writeByte(' ')
+ }
+ ps.print(n.Type)
+ if n.Init != nil {
+ parenthesize(ps, n.Init)
+ }
+}
+
+func (n *New) Traverse(fn func(AST) bool) {
+ if fn(n) {
+ n.Op.Traverse(fn)
+ if n.Place != nil {
+ n.Place.Traverse(fn)
+ }
+ n.Type.Traverse(fn)
+ if n.Init != nil {
+ n.Init.Traverse(fn)
+ }
+ }
+}
+
+func (n *New) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(n) {
+ return nil
+ }
+ op := n.Op.Copy(fn, skip)
+ var place AST
+ if n.Place != nil {
+ place = n.Place.Copy(fn, skip)
+ }
+ typ := n.Type.Copy(fn, skip)
+ var ini AST
+ if n.Init != nil {
+ ini = n.Init.Copy(fn, skip)
+ }
+ if op == nil && place == nil && typ == nil && ini == nil {
+ return fn(n)
+ }
+ if op == nil {
+ op = n.Op
+ }
+ if place == nil {
+ place = n.Place
+ }
+ if typ == nil {
+ typ = n.Type
+ }
+ if ini == nil {
+ ini = n.Init
+ }
+ n = &New{Op: op, Place: place, Type: typ, Init: ini}
+ if r := fn(n); r != nil {
+ return r
+ }
+ return n
+}
+
+func (n *New) GoString() string {
+ return n.goString(0, "")
+}
+
+func (n *New) goString(indent int, field string) string {
+ var place string
+ if n.Place == nil {
+ place = fmt.Sprintf("%*sPlace: nil", indent, "")
+ } else {
+ place = n.Place.goString(indent+2, "Place: ")
+ }
+ var ini string
+ if n.Init == nil {
+ ini = fmt.Sprintf("%*sInit: nil", indent, "")
+ } else {
+ ini = n.Init.goString(indent+2, "Init: ")
+ }
+ return fmt.Sprintf("%*s%sNew:\n%s\n%s\n%s\n%s", indent, "", field,
+ n.Op.goString(indent+2, "Op: "), place,
+ n.Type.goString(indent+2, "Type: "), ini)
+}
+
+// Literal is a literal in an expression.
+type Literal struct {
+ Type AST
+ Val string
+ Neg bool
+}
+
+// Suffixes to use for constants of the given integer type.
+var builtinTypeSuffix = map[string]string{
+ "int": "",
+ "unsigned int": "u",
+ "long": "l",
+ "unsigned long": "ul",
+ "long long": "ll",
+ "unsigned long long": "ull",
+}
+
+// Builtin float types.
+var builtinTypeFloat = map[string]bool{
+ "double": true,
+ "long double": true,
+ "float": true,
+ "__float128": true,
+ "half": true,
+}
+
+func (l *Literal) print(ps *printState) {
+ isFloat := false
+ if b, ok := l.Type.(*BuiltinType); ok {
+ if suffix, ok := builtinTypeSuffix[b.Name]; ok {
+ if l.Neg {
+ ps.writeByte('-')
+ }
+ ps.writeString(l.Val)
+ ps.writeString(suffix)
+ return
+ } else if b.Name == "bool" && !l.Neg {
+ switch l.Val {
+ case "0":
+ ps.writeString("false")
+ return
+ case "1":
+ ps.writeString("true")
+ return
+ }
+ } else {
+ isFloat = builtinTypeFloat[b.Name]
+ }
+ }
+
+ ps.writeByte('(')
+ ps.print(l.Type)
+ ps.writeByte(')')
+
+ if isFloat {
+ ps.writeByte('[')
+ }
+ if l.Neg {
+ ps.writeByte('-')
+ }
+ ps.writeString(l.Val)
+ if isFloat {
+ ps.writeByte(']')
+ }
+}
+
+func (l *Literal) Traverse(fn func(AST) bool) {
+ if fn(l) {
+ l.Type.Traverse(fn)
+ }
+}
+
+func (l *Literal) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(l) {
+ return nil
+ }
+ typ := l.Type.Copy(fn, skip)
+ if typ == nil {
+ return fn(l)
+ }
+ l = &Literal{Type: typ, Val: l.Val, Neg: l.Neg}
+ if r := fn(l); r != nil {
+ return r
+ }
+ return l
+}
+
+func (l *Literal) GoString() string {
+ return l.goString(0, "")
+}
+
+func (l *Literal) goString(indent int, field string) string {
+ var neg string
+ if l.Neg {
+ neg = " Neg: true"
+ }
+ return fmt.Sprintf("%*s%sLiteral:%s\n%s\n%*sVal: %s", indent, "", field,
+ neg, l.Type.goString(indent+2, "Type: "),
+ indent+2, "", l.Val)
+}
+
+// ExprList is a list of expressions, typically arguments to a
+// function call in an expression.
+type ExprList struct {
+ Exprs []AST
+}
+
+func (el *ExprList) print(ps *printState) {
+ for i, e := range el.Exprs {
+ if i > 0 {
+ ps.writeString(", ")
+ }
+ ps.print(e)
+ }
+}
+
+func (el *ExprList) Traverse(fn func(AST) bool) {
+ if fn(el) {
+ for _, e := range el.Exprs {
+ e.Traverse(fn)
+ }
+ }
+}
+
+func (el *ExprList) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(el) {
+ return nil
+ }
+ exprs := make([]AST, len(el.Exprs))
+ changed := false
+ for i, e := range el.Exprs {
+ ec := e.Copy(fn, skip)
+ if ec == nil {
+ exprs[i] = e
+ } else {
+ exprs[i] = ec
+ changed = true
+ }
+ }
+ if !changed {
+ return fn(el)
+ }
+ el = &ExprList{Exprs: exprs}
+ if r := fn(el); r != nil {
+ return r
+ }
+ return el
+}
+
+func (el *ExprList) GoString() string {
+ return el.goString(0, "")
+}
+
+func (el *ExprList) goString(indent int, field string) string {
+ if len(el.Exprs) == 0 {
+ return fmt.Sprintf("%*s%sExprList: nil", indent, "", field)
+ }
+ s := fmt.Sprintf("%*s%sExprList:", indent, "", field)
+ for i, e := range el.Exprs {
+ s += "\n"
+ s += e.goString(indent+2, fmt.Sprintf("%d: ", i))
+ }
+ return s
+}
+
+// InitializerList is an initializer list: an optional type with a
+// list of expressions.
+type InitializerList struct {
+ Type AST
+ Exprs AST
+}
+
+func (il *InitializerList) print(ps *printState) {
+ if il.Type != nil {
+ ps.print(il.Type)
+ }
+ ps.writeByte('{')
+ ps.print(il.Exprs)
+ ps.writeByte('}')
+}
+
+func (il *InitializerList) Traverse(fn func(AST) bool) {
+ if fn(il) {
+ if il.Type != nil {
+ il.Type.Traverse(fn)
+ }
+ il.Exprs.Traverse(fn)
+ }
+}
+
+func (il *InitializerList) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(il) {
+ return nil
+ }
+ var typ AST
+ if il.Type != nil {
+ typ = il.Type.Copy(fn, skip)
+ }
+ exprs := il.Exprs.Copy(fn, skip)
+ if typ == nil && exprs == nil {
+ return fn(il)
+ }
+ if typ == nil {
+ typ = il.Type
+ }
+ if exprs == nil {
+ exprs = il.Exprs
+ }
+ il = &InitializerList{Type: typ, Exprs: exprs}
+ if r := fn(il); r != nil {
+ return r
+ }
+ return il
+}
+
+func (il *InitializerList) GoString() string {
+ return il.goString(0, "")
+}
+
+func (il *InitializerList) goString(indent int, field string) string {
+ var t string
+ if il.Type == nil {
+ t = fmt.Sprintf("%*sType: nil", indent+2, "")
+ } else {
+ t = il.Type.goString(indent+2, "Type: ")
+ }
+ return fmt.Sprintf("%*s%sInitializerList:\n%s\n%s", indent, "", field,
+ t, il.Exprs.goString(indent+2, "Exprs: "))
+}
+
+// DefaultArg holds a default argument for a local name.
+type DefaultArg struct {
+ Num int
+ Arg AST
+}
+
+func (da *DefaultArg) print(ps *printState) {
+ fmt.Fprintf(&ps.buf, "{default arg#%d}::", da.Num+1)
+ ps.print(da.Arg)
+}
+
+func (da *DefaultArg) Traverse(fn func(AST) bool) {
+ if fn(da) {
+ da.Arg.Traverse(fn)
+ }
+}
+
+func (da *DefaultArg) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(da) {
+ return nil
+ }
+ arg := da.Arg.Copy(fn, skip)
+ if arg == nil {
+ return fn(da)
+ }
+ da = &DefaultArg{Num: da.Num, Arg: arg}
+ if r := fn(da); r != nil {
+ return r
+ }
+ return da
+}
+
+func (da *DefaultArg) GoString() string {
+ return da.goString(0, "")
+}
+
+func (da *DefaultArg) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sDefaultArg: Num: %d\n%s", indent, "", field, da.Num,
+ da.Arg.goString(indent+2, "Arg: "))
+}
+
+// Closure is a closure, or lambda expression.
+type Closure struct {
+ Types []AST
+ Num int
+}
+
+func (cl *Closure) print(ps *printState) {
+ ps.writeString("{lambda(")
+ for i, t := range cl.Types {
+ if i > 0 {
+ ps.writeString(", ")
+ }
+ ps.print(t)
+ }
+ ps.writeString(fmt.Sprintf(")#%d}", cl.Num+1))
+}
+
+func (cl *Closure) Traverse(fn func(AST) bool) {
+ if fn(cl) {
+ for _, t := range cl.Types {
+ t.Traverse(fn)
+ }
+ }
+}
+
+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
+ for i, t := range cl.Types {
+ tc := t.Copy(fn, skip)
+ if tc == nil {
+ types[i] = t
+ } else {
+ types[i] = tc
+ changed = true
+ }
+ }
+ if !changed {
+ return fn(cl)
+ }
+ cl = &Closure{Types: types, Num: cl.Num}
+ if r := fn(cl); r != nil {
+ return r
+ }
+ return cl
+}
+
+func (cl *Closure) GoString() string {
+ return cl.goString(0, "")
+}
+
+func (cl *Closure) goString(indent int, field string) string {
+ var types string
+ if len(cl.Types) == 0 {
+ types = fmt.Sprintf("%*sTypes: nil", indent+2, "")
+ } else {
+ types = fmt.Sprintf("%*sTypes:", indent+2, "")
+ for i, t := range cl.Types {
+ types += "\n"
+ types += t.goString(indent+4, fmt.Sprintf("%d: ", i))
+ }
+ }
+ return fmt.Sprintf("%*s%sClosure: Num: %d\n%s", indent, "", field, cl.Num, types)
+}
+
+// UnnamedType is an unnamed type, that just has an index.
+type UnnamedType struct {
+ Num int
+}
+
+func (ut *UnnamedType) print(ps *printState) {
+ ps.writeString(fmt.Sprintf("{unnamed type#%d}", ut.Num+1))
+}
+
+func (ut *UnnamedType) Traverse(fn func(AST) bool) {
+ fn(ut)
+}
+
+func (ut *UnnamedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(ut) {
+ return nil
+ }
+ return fn(ut)
+}
+
+func (ut *UnnamedType) GoString() string {
+ return ut.goString(0, "")
+}
+
+func (ut *UnnamedType) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sUnnamedType: Num: %d", indent, "", field, ut.Num)
+}
+
+// Clone is a clone of a function, with a distinguishing suffix.
+type Clone struct {
+ Base AST
+ Suffix string
+}
+
+func (c *Clone) print(ps *printState) {
+ ps.print(c.Base)
+ ps.writeString(fmt.Sprintf(" [clone %s]", c.Suffix))
+}
+
+func (c *Clone) Traverse(fn func(AST) bool) {
+ if fn(c) {
+ c.Base.Traverse(fn)
+ }
+}
+
+func (c *Clone) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(c) {
+ return nil
+ }
+ base := c.Base.Copy(fn, skip)
+ if base == nil {
+ return fn(c)
+ }
+ c = &Clone{Base: base, Suffix: c.Suffix}
+ if r := fn(c); r != nil {
+ return r
+ }
+ return c
+}
+
+func (c *Clone) GoString() string {
+ return c.goString(0, "")
+}
+
+func (c *Clone) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sClone: Suffix: %s\n%s", indent, "", field,
+ c.Suffix, c.Base.goString(indent+2, "Base: "))
+}
+
+// Special is a special symbol, printed as a prefix plus another
+// value.
+type Special struct {
+ Prefix string
+ Val AST
+}
+
+func (s *Special) print(ps *printState) {
+ ps.writeString(s.Prefix)
+ ps.print(s.Val)
+}
+
+func (s *Special) Traverse(fn func(AST) bool) {
+ if fn(s) {
+ s.Val.Traverse(fn)
+ }
+}
+
+func (s *Special) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(s) {
+ return nil
+ }
+ val := s.Val.Copy(fn, skip)
+ if val == nil {
+ return fn(s)
+ }
+ s = &Special{Prefix: s.Prefix, Val: val}
+ if r := fn(s); r != nil {
+ return r
+ }
+ return s
+}
+
+func (s *Special) GoString() string {
+ return s.goString(0, "")
+}
+
+func (s *Special) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sSpecial: Prefix: %s\n%s", indent, "", field,
+ s.Prefix, s.Val.goString(indent+2, "Val: "))
+}
+
+// Special2 is like special, but uses two values.
+type Special2 struct {
+ Prefix string
+ Val1 AST
+ Middle string
+ Val2 AST
+}
+
+func (s *Special2) print(ps *printState) {
+ ps.writeString(s.Prefix)
+ ps.print(s.Val1)
+ ps.writeString(s.Middle)
+ ps.print(s.Val2)
+}
+
+func (s *Special2) Traverse(fn func(AST) bool) {
+ if fn(s) {
+ s.Val1.Traverse(fn)
+ s.Val2.Traverse(fn)
+ }
+}
+
+func (s *Special2) Copy(fn func(AST) AST, skip func(AST) bool) AST {
+ if skip(s) {
+ return nil
+ }
+ val1 := s.Val1.Copy(fn, skip)
+ val2 := s.Val2.Copy(fn, skip)
+ if val1 == nil && val2 == nil {
+ return fn(s)
+ }
+ if val1 == nil {
+ val1 = s.Val1
+ }
+ if val2 == nil {
+ val2 = s.Val2
+ }
+ s = &Special2{Prefix: s.Prefix, Val1: val1, Middle: s.Middle, Val2: val2}
+ if r := fn(s); r != nil {
+ return r
+ }
+ return s
+}
+
+func (s *Special2) GoString() string {
+ return s.goString(0, "")
+}
+
+func (s *Special2) goString(indent int, field string) string {
+ return fmt.Sprintf("%*s%sSpecial2: Prefix: %s\n%s\n%*sMiddle: %s\n%s", indent, "", field,
+ s.Prefix, s.Val1.goString(indent+2, "Val1: "),
+ indent+2, "", s.Middle, s.Val2.goString(indent+2, "Val2: "))
+}
+
+// Print the inner types.
+func (ps *printState) printInner(prefixOnly bool) []AST {
+ var save []AST
+ var psave *[]AST
+ if prefixOnly {
+ psave = &save
+ }
+ for len(ps.inner) > 0 {
+ ps.printOneInner(psave)
+ }
+ return save
+}
+
+// innerPrinter is an interface for types that can print themselves as
+// inner types.
+type innerPrinter interface {
+ printInner(*printState)
+}
+
+// Print the most recent inner type. If save is not nil, only print
+// prefixes.
+func (ps *printState) printOneInner(save *[]AST) {
+ if len(ps.inner) == 0 {
+ panic("printOneInner called with no inner types")
+ }
+ ln := len(ps.inner)
+ a := ps.inner[ln-1]
+ ps.inner = ps.inner[:ln-1]
+
+ if save != nil {
+ if _, ok := a.(*MethodWithQualifiers); ok {
+ *save = append(*save, a)
+ return
+ }
+ }
+
+ if ip, ok := a.(innerPrinter); ok {
+ ip.printInner(ps)
+ } else {
+ ps.print(a)
+ }
+}
+
+// isEmpty returns whether printing a will not print anything.
+func (ps *printState) isEmpty(a AST) bool {
+ switch a := a.(type) {
+ case *ArgumentPack:
+ return len(a.Args) == 0
+ case *ExprList:
+ return len(a.Exprs) == 0
+ case *PackExpansion:
+ return a.Pack != nil && ps.isEmpty(a.Base)
+ default:
+ return false
+ }
+}
diff --git a/vendor/github.com/ianlancetaylor/demangle/c++filt.go b/vendor/github.com/ianlancetaylor/demangle/c++filt.go
new file mode 100644
index 000000000..7ba817c9f
--- /dev/null
+++ b/vendor/github.com/ianlancetaylor/demangle/c++filt.go
@@ -0,0 +1,144 @@
+// Copyright 2015 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.
+
+// +build ignore
+
+// This is a program that works like the GNU c++filt program.
+// It's here for testing purposes and as an example.
+
+package main
+
+import (
+ "bufio"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "unicode"
+
+ "github.com/ianlancetaylor/demangle"
+)
+
+func flagUsage() {
+ usage(os.Stderr, 2)
+}
+
+func usage(w io.Writer, status int) {
+ fmt.Fprintf(w, "Usage: %s [options] [mangled names]\n", os.Args[0])
+ flag.CommandLine.SetOutput(w)
+ flag.PrintDefaults()
+ fmt.Fprintln(w, `Demangled names are displayed to stdout
+If a name cannot be demangled it is just echoed to stdout.
+If no names are provided on the command line, stdin is read.`)
+ os.Exit(status)
+}
+
+var stripUnderscore = flag.Bool("_", false, "Ignore first leading underscore")
+var noParams = flag.Bool("p", false, "Do not display function argument types")
+var noVerbose = flag.Bool("i", false, "Do not show implementation details (if any)")
+var help = flag.Bool("h", false, "Display help information")
+var debug = flag.Bool("d", false, "Display debugging information for strings on command line")
+
+// Unimplemented c++filt flags:
+// -n (opposite of -_)
+// -t (demangle types)
+// -s (set demangling style)
+// -V (print version information)
+
+// Characters considered to be part of a symbol.
+const symbolChars = "_$."
+
+func main() {
+ flag.Usage = func() { usage(os.Stderr, 1) }
+ flag.Parse()
+
+ if *help {
+ usage(os.Stdout, 0)
+ }
+
+ out := bufio.NewWriter(os.Stdout)
+
+ if flag.NArg() > 0 {
+ for _, f := range flag.Args() {
+ if *debug {
+ a, err := demangle.ToAST(f, options()...)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %v\n", f, err)
+ } else {
+ fmt.Fprintf(out, "%#v\n", a)
+ }
+ } else {
+ doDemangle(out, f)
+ }
+ out.WriteByte('\n')
+ }
+ if err := out.Flush(); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+ return
+ }
+
+ scanner := bufio.NewScanner(bufio.NewReader(os.Stdin))
+ for scanner.Scan() {
+ line := scanner.Text()
+ start := -1
+ for i, c := range line {
+ if unicode.IsLetter(c) || unicode.IsNumber(c) || strings.ContainsRune(symbolChars, c) {
+ if start < 0 {
+ start = i
+ }
+ } else {
+ if start >= 0 {
+ doDemangle(out, line[start:i])
+ }
+ out.WriteRune(c)
+ start = -1
+ }
+ }
+ if start >= 0 {
+ doDemangle(out, line[start:])
+ start = -1
+ }
+ out.WriteByte('\n')
+ if err := out.Flush(); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+ }
+}
+
+// Demangle a string just as the GNU c++filt program does.
+func doDemangle(out *bufio.Writer, name string) {
+ skip := 0
+ if name[0] == '.' || name[0] == '$' {
+ skip++
+ }
+ if *stripUnderscore && name[skip] == '_' {
+ skip++
+ }
+ result := demangle.Filter(name[skip:], options()...)
+ if result == name[skip:] {
+ out.WriteString(name)
+ } else {
+ if name[0] == '.' {
+ out.WriteByte('.')
+ }
+ out.WriteString(result)
+ }
+}
+
+// options returns the demangling options to use based on the command
+// line flags.
+func options() []demangle.Option {
+ var options []demangle.Option
+ if *noParams {
+ options = append(options, demangle.NoParams)
+ }
+ if !*noVerbose {
+ options = append(options, demangle.Verbose)
+ }
+ return options
+}
diff --git a/vendor/github.com/ianlancetaylor/demangle/demangle.go b/vendor/github.com/ianlancetaylor/demangle/demangle.go
new file mode 100644
index 000000000..c46744017
--- /dev/null
+++ b/vendor/github.com/ianlancetaylor/demangle/demangle.go
@@ -0,0 +1,2501 @@
+// Copyright 2015 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 defines functions that demangle GCC/LLVM C++ symbol names.
+// This package recognizes names that were mangled according to the C++ ABI
+// defined at http://codesourcery.com/cxx-abi/.
+package demangle
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+)
+
+// 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")
+
+// Option is the type of demangler options.
+type Option int
+
+const (
+ // The NoParams option disables demangling of function parameters.
+ NoParams Option = iota
+
+ // The NoTemplateParams option disables demangling of template parameters.
+ NoTemplateParams
+
+ // The NoClones option disables inclusion of clone suffixes.
+ // NoParams implies NoClones.
+ NoClones
+
+ // The Verbose option turns on more verbose demangling.
+ Verbose
+)
+
+// Filter demangles a C++ symbol name, returning the human-readable C++ name.
+// If any error occurs during demangling, the input string is returned.
+func Filter(name string, options ...Option) string {
+ ret, err := ToString(name, options...)
+ if err != nil {
+ return name
+ }
+ return ret
+}
+
+// ToString demangles a C++ symbol name, returning 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.
+func ToString(name string, options ...Option) (string, error) {
+ a, err := ToAST(name, options...)
+ if err != nil {
+ return "", err
+ }
+ return ASTToString(a, options...), nil
+}
+
+// ToAST demangles a C++ symbol name into an abstract syntax tree
+// representing the symbol.
+// If the NoParams option is passed, and the name has a function type,
+// 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.
+func ToAST(name string, options ...Option) (AST, error) {
+ if strings.HasPrefix(name, "_Z") {
+ a, err := doDemangle(name[2:], options...)
+ return a, adjustErr(err, 2)
+ }
+
+ const prefix = "_GLOBAL_"
+ if strings.HasPrefix(name, prefix) {
+ // The standard demangler ignores NoParams for global
+ // constructors. We are compatible.
+ i := 0
+ for i < len(options) {
+ if options[i] == NoParams {
+ options = append(options[:i], options[i+1:]...)
+ } else {
+ i++
+ }
+ }
+ a, err := globalCDtorName(name[len(prefix):], options...)
+ return a, adjustErr(err, len(prefix))
+ }
+
+ return nil, ErrNotMangledName
+}
+
+// globalCDtorName demangles a global constructor/destructor symbol name.
+// The parameter is the string following the "_GLOBAL_" prefix.
+func globalCDtorName(name string, options ...Option) (AST, error) {
+ if len(name) < 4 {
+ return nil, ErrNotMangledName
+ }
+ switch name[0] {
+ case '.', '_', '$':
+ default:
+ return nil, ErrNotMangledName
+ }
+
+ var ctor bool
+ switch name[1] {
+ case 'I':
+ ctor = true
+ case 'D':
+ ctor = false
+ default:
+ return nil, ErrNotMangledName
+ }
+
+ if name[2] != '_' {
+ return nil, ErrNotMangledName
+ }
+
+ if !strings.HasPrefix(name[3:], "_Z") {
+ return &GlobalCDtor{Ctor: ctor, Key: &Name{Name: name}}, nil
+ } else {
+ a, err := doDemangle(name[5:], options...)
+ if err != nil {
+ return nil, adjustErr(err, 5)
+ }
+ return &GlobalCDtor{Ctor: ctor, Key: a}, nil
+ }
+}
+
+// The doDemangle function is the entry point into the demangler proper.
+func doDemangle(name string, options ...Option) (ret AST, err error) {
+ // 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 = nil
+ err = de
+ return
+ }
+ panic(r)
+ }
+ }()
+
+ params := true
+ clones := true
+ verbose := false
+ for _, o := range options {
+ switch o {
+ 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
+ default:
+ return nil, fmt.Errorf("unrecognized demangler option %v", o)
+ }
+ }
+
+ st := &state{str: name, verbose: verbose}
+ a := st.encoding(params)
+
+ // Accept a clone suffix.
+ if clones {
+ for len(st.str) > 1 && st.str[0] == '.' && (isLower(st.str[1]) || st.str[1] == '_' || isDigit(st.str[1])) {
+ a = st.cloneSuffix(a)
+ }
+ }
+
+ if clones && len(st.str) > 0 {
+ st.fail("unparsed characters at end of mangled name")
+ }
+
+ return a, nil
+}
+
+// A state holds the current state of demangling a string.
+type state struct {
+ str string // remainder of string to demangle
+ verbose bool // whether to use verbose demangling
+ off int // offset of str within original string
+ subs substitutions // substitutions
+ templates []*Template // templates being processed
+}
+
+// copy returns a copy of the current state.
+func (st *state) copy() *state {
+ n := new(state)
+ *n = *st
+ return n
+}
+
+// fail panics with demangleErr, to be caught in doDemangle.
+func (st *state) fail(err string) {
+ panic(demangleErr{err: err, off: st.off})
+}
+
+// failEarlier is like fail, but decrements the offset to indicate
+// that the point of failure occurred earlier in the string.
+func (st *state) failEarlier(err string, dec int) {
+ if st.off < dec {
+ panic("internal error")
+ }
+ panic(demangleErr{err: err, off: st.off - dec})
+}
+
+// advance advances the current string offset.
+func (st *state) advance(add int) {
+ if len(st.str) < add {
+ panic("internal error")
+ }
+ st.str = st.str[add:]
+ st.off += add
+}
+
+// checkChar requires that the next character in the string be c, and
+// advances past it.
+func (st *state) checkChar(c byte) {
+ if len(st.str) == 0 || st.str[0] != c {
+ panic("internal error")
+ }
+ st.advance(1)
+}
+
+// A demangleErr is an error at a specific offset in the mangled
+// string.
+type demangleErr struct {
+ err string
+ off int
+}
+
+// Error implements the builtin error interface for demangleErr.
+func (de demangleErr) Error() string {
+ return fmt.Sprintf("%s at %d", de.err, de.off)
+}
+
+// adjustErr adjusts the position of err, if it is a demangleErr,
+// and returns err.
+func adjustErr(err error, adj int) error {
+ if err == nil {
+ return nil
+ }
+ if de, ok := err.(demangleErr); ok {
+ de.off += adj
+ return de
+ }
+ return err
+}
+
+// encoding ::= <(function) name> <bare-function-type>
+// <(data) name>
+// <special-name>
+func (st *state) encoding(params bool) AST {
+ if len(st.str) < 1 {
+ st.fail("expected encoding")
+ }
+
+ if st.str[0] == 'G' || st.str[0] == 'T' {
+ return st.specialName()
+ }
+
+ a := st.name()
+ a = simplify(a)
+
+ if !params {
+ // Don't demangle the parameters.
+
+ // Strip CV-qualifiers, as they apply to the 'this'
+ // parameter, and are not output by the standard
+ // demangler without parameters.
+ if mwq, ok := a.(*MethodWithQualifiers); ok {
+ a = mwq.Method
+ }
+
+ // If this is a local name, there may be CV-qualifiers
+ // on the name that really apply to the top level, and
+ // therefore must be discarded when discarding
+ // parameters. This can happen when parsing a class
+ // that is local to a function.
+ if q, ok := a.(*Qualified); ok && q.LocalName {
+ p := &q.Name
+ if da, ok := (*p).(*DefaultArg); ok {
+ p = &da.Arg
+ }
+ if mwq, ok := (*p).(*MethodWithQualifiers); ok {
+ *p = mwq.Method
+ }
+ }
+
+ return a
+ }
+
+ if len(st.str) == 0 || st.str[0] == 'E' {
+ // There are no parameters--this is a data symbol, not
+ // a function symbol.
+ return a
+ }
+
+ check := a
+ mwq, _ := check.(*MethodWithQualifiers)
+ if mwq != nil {
+ check = mwq.Method
+ }
+ template, _ := check.(*Template)
+ if template != nil {
+ st.templates = append(st.templates, template)
+ }
+
+ ft := st.bareFunctionType(hasReturnType(a))
+
+ if template != nil {
+ st.templates = st.templates[:len(st.templates)-1]
+ }
+
+ ft = simplify(ft)
+
+ // Any top-level qualifiers belong to the function type.
+ if mwq != nil {
+ a = mwq.Method
+ mwq.Method = ft
+ ft = mwq
+ }
+ if q, ok := a.(*Qualified); ok && q.LocalName {
+ p := &q.Name
+ if da, ok := (*p).(*DefaultArg); ok {
+ p = &da.Arg
+ }
+ if mwq, ok := (*p).(*MethodWithQualifiers); ok {
+ *p = mwq.Method
+ mwq.Method = ft
+ ft = mwq
+ }
+ }
+
+ return &Typed{Name: a, Type: ft}
+}
+
+// hasReturnType returns whether the mangled form of a will have a
+// return type.
+func hasReturnType(a AST) bool {
+ switch a := a.(type) {
+ case *Template:
+ return !isCDtorConversion(a.Name)
+ case *TypeWithQualifiers:
+ return hasReturnType(a.Base)
+ case *MethodWithQualifiers:
+ return hasReturnType(a.Method)
+ default:
+ return false
+ }
+}
+
+// isCDtorConversion returns when an AST is a constructor, a
+// destructor, or a conversion operator.
+func isCDtorConversion(a AST) bool {
+ switch a := a.(type) {
+ case *Qualified:
+ return isCDtorConversion(a.Name)
+ case *Constructor, *Destructor, *Cast:
+ return true
+ default:
+ return false
+ }
+}
+
+// <tagged-name> ::= <name> B <source-name>
+func (st *state) taggedName(a AST) AST {
+ for len(st.str) > 0 && st.str[0] == 'B' {
+ st.advance(1)
+ tag := st.sourceName()
+ a = &TaggedName{Name: a, Tag: tag}
+ }
+ return a
+}
+
+// <name> ::= <nested-name>
+// ::= <unscoped-name>
+// ::= <unscoped-template-name> <template-args>
+// ::= <local-name>
+//
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name>
+//
+// <unscoped-template-name> ::= <unscoped-name>
+// ::= <substitution>
+func (st *state) name() AST {
+ if len(st.str) < 1 {
+ st.fail("expected name")
+ }
+ switch st.str[0] {
+ case 'N':
+ return st.nestedName()
+ case 'Z':
+ return st.localName()
+ case 'U':
+ a, isCast := st.unqualifiedName()
+ if isCast {
+ st.setTemplate(a, nil)
+ }
+ return a
+ case 'S':
+ if len(st.str) < 2 {
+ st.advance(1)
+ st.fail("expected substitution index")
+ }
+ var a AST
+ isCast := false
+ subst := false
+ if st.str[1] == 't' {
+ st.advance(2)
+ a, isCast = st.unqualifiedName()
+ a = &Qualified{Scope: &Name{Name: "std"}, Name: a, LocalName: false}
+ } else {
+ a = st.substitution(false)
+ subst = true
+ }
+ if len(st.str) > 0 && st.str[0] == 'I' {
+ // This can only happen if we saw
+ // <unscoped-template-name> and are about to see
+ // <template-args>. <unscoped-template-name> is a
+ // substitution candidate if it did not come from a
+ // substitution.
+ if !subst {
+ st.subs.add(a)
+ }
+ args := st.templateArgs()
+ tmpl := &Template{Name: a, Args: args}
+ if isCast {
+ st.setTemplate(a, tmpl)
+ st.clearTemplateArgs(args)
+ isCast = false
+ }
+ a = tmpl
+ }
+ if isCast {
+ st.setTemplate(a, nil)
+ }
+ return a
+
+ default:
+ a, isCast := st.unqualifiedName()
+ if len(st.str) > 0 && st.str[0] == 'I' {
+ st.subs.add(a)
+ args := st.templateArgs()
+ tmpl := &Template{Name: a, Args: args}
+ if isCast {
+ st.setTemplate(a, tmpl)
+ st.clearTemplateArgs(args)
+ isCast = false
+ }
+ a = tmpl
+ }
+ if isCast {
+ st.setTemplate(a, nil)
+ }
+ return a
+ }
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+func (st *state) nestedName() AST {
+ st.checkChar('N')
+ q := st.cvQualifiers()
+ r := st.refQualifier()
+ a := st.prefix()
+ if len(q) > 0 || r != "" {
+ a = &MethodWithQualifiers{Method: a, Qualifiers: q, RefQualifier: r}
+ }
+ if len(st.str) == 0 || st.str[0] != 'E' {
+ st.fail("expected E after nested name")
+ }
+ st.advance(1)
+ return a
+}
+
+// <prefix> ::= <prefix> <unqualified-name>
+// ::= <template-prefix> <template-args>
+// ::= <template-param>
+// ::= <decltype>
+// ::=
+// ::= <substitution>
+//
+// <template-prefix> ::= <prefix> <(template) unqualified-name>
+// ::= <template-param>
+// ::= <substitution>
+//
+// <decltype> ::= Dt <expression> E
+// ::= DT <expression> E
+func (st *state) prefix() AST {
+ var a AST
+
+ // The last name seen, for a constructor/destructor.
+ var last AST
+
+ getLast := func(a AST) AST {
+ for {
+ if t, ok := a.(*Template); ok {
+ a = t.Name
+ } else if q, ok := a.(*Qualified); ok {
+ a = q.Name
+ } else if t, ok := a.(*TaggedName); ok {
+ a = t.Name
+ } else {
+ return a
+ }
+ }
+ }
+
+ isCast := false
+ for {
+ if len(st.str) == 0 {
+ st.fail("expected prefix")
+ }
+ var next AST
+
+ c := st.str[0]
+ if isDigit(c) || isLower(c) || c == 'U' || c == 'L' {
+ un, isUnCast := st.unqualifiedName()
+ next = un
+ if isUnCast {
+ isCast = true
+ }
+ } else {
+ switch st.str[0] {
+ case 'C':
+ if len(st.str) < 2 {
+ st.fail("expected constructor type")
+ }
+ if last == nil {
+ st.fail("constructor before name is seen")
+ }
+ st.advance(2)
+ next = &Constructor{Name: getLast(last)}
+ case 'D':
+ if len(st.str) > 1 && (st.str[1] == 'T' || st.str[1] == 't') {
+ next = st.demangleType(false)
+ } else {
+ if len(st.str) < 2 {
+ st.fail("expected destructor type")
+ }
+ if last == nil {
+ st.fail("destructor before name is seen")
+ }
+ st.advance(2)
+ next = &Destructor{Name: getLast(last)}
+ }
+ case 'S':
+ next = st.substitution(true)
+ case 'I':
+ if a == nil {
+ st.fail("unexpected template arguments")
+ }
+ var args []AST
+ args = st.templateArgs()
+ tmpl := &Template{Name: a, Args: args}
+ if isCast {
+ st.setTemplate(a, tmpl)
+ st.clearTemplateArgs(args)
+ isCast = false
+ }
+ a = nil
+ next = tmpl
+ case 'T':
+ next = st.templateParam()
+ case 'E':
+ if a == nil {
+ st.fail("expected prefix")
+ }
+ if isCast {
+ st.setTemplate(a, nil)
+ }
+ return a
+ case 'M':
+ if a == nil {
+ st.fail("unexpected lambda initializer")
+ }
+ // This is the initializer scope for a
+ // lambda. We don't need to record
+ // it. The normal code will treat the
+ // variable has a type scope, which
+ // gives appropriate output.
+ st.advance(1)
+ continue
+ default:
+ st.fail("unrecognized letter in prefix")
+ }
+ }
+ last = next
+ if a == nil {
+ a = next
+ } else {
+ a = &Qualified{Scope: a, Name: next, LocalName: false}
+ }
+
+ if c != 'S' && (len(st.str) == 0 || st.str[0] != 'E') {
+ st.subs.add(a)
+ }
+ }
+}
+
+// <unqualified-name> ::= <operator-name>
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <local-source-name>
+//
+// <local-source-name> ::= L <source-name> <discriminator>
+func (st *state) unqualifiedName() (r AST, isCast bool) {
+ if len(st.str) < 1 {
+ st.fail("expected unqualified name")
+ }
+ var a AST
+ isCast = false
+ c := st.str[0]
+ if isDigit(c) {
+ a = st.sourceName()
+ } else if isLower(c) {
+ a, _ = st.operatorName(false)
+ if _, ok := a.(*Cast); ok {
+ isCast = true
+ }
+ if op, ok := a.(*Operator); ok && op.Name == `operator"" ` {
+ n := st.sourceName()
+ a = &Unary{Op: op, Expr: n, Suffix: false, SizeofType: false}
+ }
+ } else {
+ switch c {
+ case 'C', 'D':
+ st.fail("constructor/destructor not in nested name")
+ case 'L':
+ st.advance(1)
+ a = st.sourceName()
+ a = st.discriminator(a)
+ case 'U':
+ if len(st.str) < 2 {
+ st.advance(1)
+ st.fail("expected closure or unnamed type")
+ }
+ c := st.str[1]
+ switch c {
+ case 'l':
+ a = st.closureTypeName()
+ case 't':
+ a = st.unnamedTypeName()
+ default:
+ st.advance(1)
+ st.fail("expected closure or unnamed type")
+ }
+ default:
+ st.fail("expected unqualified name")
+ }
+ }
+
+ if len(st.str) > 0 && st.str[0] == 'B' {
+ a = st.taggedName(a)
+ }
+
+ return a, isCast
+}
+
+// <source-name> ::= <(positive length) number> <identifier>
+// identifier ::= <(unqualified source code identifier)>
+func (st *state) sourceName() AST {
+ val := st.number()
+ if val <= 0 {
+ st.fail("expected positive number")
+ }
+ if len(st.str) < val {
+ st.fail("not enough characters for identifier")
+ }
+ id := st.str[:val]
+ st.advance(val)
+
+ // Look for GCC encoding of anonymous namespace, and make it
+ // more friendly.
+ const anonPrefix = "_GLOBAL_"
+ if strings.HasPrefix(id, anonPrefix) && len(id) > len(anonPrefix)+2 {
+ c1 := id[len(anonPrefix)]
+ c2 := id[len(anonPrefix)+1]
+ if (c1 == '.' || c1 == '_' || c1 == '$') && c2 == 'N' {
+ id = "(anonymous namespace)"
+ }
+ }
+
+ n := &Name{Name: id}
+ return n
+}
+
+// number ::= [n] <(non-negative decimal integer)>
+func (st *state) number() int {
+ neg := false
+ if len(st.str) > 0 && st.str[0] == 'n' {
+ neg = true
+ st.advance(1)
+ }
+ if len(st.str) == 0 || !isDigit(st.str[0]) {
+ st.fail("missing number")
+ }
+ val := 0
+ for len(st.str) > 0 && isDigit(st.str[0]) {
+ // Number picked to ensure we can't overflow with 32-bit int.
+ // Any very large number here is bogus.
+ if val >= 0x80000000/10-10 {
+ st.fail("numeric overflow")
+ }
+ val = val*10 + int(st.str[0]-'0')
+ st.advance(1)
+ }
+ if neg {
+ val = -val
+ }
+ return val
+}
+
+// An operator is the demangled name, and the number of arguments it
+// takes in an expression.
+type operator struct {
+ name string
+ args int
+}
+
+// The operators map maps the mangled operator names to information
+// about them.
+var operators = map[string]operator{
+ "aN": {"&=", 2},
+ "aS": {"=", 2},
+ "aa": {"&&", 2},
+ "ad": {"&", 1},
+ "an": {"&", 2},
+ "at": {"alignof ", 1},
+ "az": {"alignof ", 1},
+ "cc": {"const_cast", 2},
+ "cl": {"()", 2},
+ "cm": {",", 2},
+ "co": {"~", 1},
+ "dV": {"/=", 2},
+ "da": {"delete[] ", 1},
+ "dc": {"dynamic_cast", 2},
+ "de": {"*", 1},
+ "dl": {"delete ", 1},
+ "ds": {".*", 2},
+ "dt": {".", 2},
+ "dv": {"/", 2},
+ "eO": {"^=", 2},
+ "eo": {"^", 2},
+ "eq": {"==", 2},
+ "fl": {"...", 2},
+ "fr": {"...", 2},
+ "fL": {"...", 3},
+ "fR": {"...", 3},
+ "ge": {">=", 2},
+ "gs": {"::", 1},
+ "gt": {">", 2},
+ "ix": {"[]", 2},
+ "lS": {"<<=", 2},
+ "le": {"<=", 2},
+ "li": {`operator"" `, 1},
+ "ls": {"<<", 2},
+ "lt": {"<", 2},
+ "mI": {"-=", 2},
+ "mL": {"*=", 2},
+ "mi": {"-", 2},
+ "ml": {"*", 2},
+ "mm": {"--", 1},
+ "na": {"new[]", 3},
+ "ne": {"!=", 2},
+ "ng": {"-", 1},
+ "nt": {"!", 1},
+ "nw": {"new", 3},
+ "oR": {"|=", 2},
+ "oo": {"||", 2},
+ "or": {"|", 2},
+ "pL": {"+=", 2},
+ "pl": {"+", 2},
+ "pm": {"->*", 2},
+ "pp": {"++", 1},
+ "ps": {"+", 1},
+ "pt": {"->", 2},
+ "qu": {"?", 3},
+ "rM": {"%=", 2},
+ "rS": {">>=", 2},
+ "rc": {"reinterpret_cast", 2},
+ "rm": {"%", 2},
+ "rs": {">>", 2},
+ "sc": {"static_cast", 2},
+ "st": {"sizeof ", 1},
+ "sz": {"sizeof ", 1},
+ "tr": {"throw", 0},
+ "tw": {"throw ", 1},
+}
+
+// operator_name ::= many different two character encodings.
+// ::= cv <type>
+// ::= v <digit> <source-name>
+//
+// We need to know whether we are in an expression because it affects
+// how we handle template parameters in the type of a cast operator.
+func (st *state) operatorName(inExpression bool) (AST, int) {
+ if len(st.str) < 2 {
+ st.fail("missing operator code")
+ }
+ code := st.str[:2]
+ st.advance(2)
+ if code[0] == 'v' && isDigit(code[1]) {
+ name := st.sourceName()
+ return &Operator{Name: name.(*Name).Name}, int(code[1] - '0')
+ } else if code == "cv" {
+ // Push a nil on templates to indicate that template
+ // parameters will have their template filled in
+ // later.
+ if !inExpression {
+ st.templates = append(st.templates, nil)
+ }
+
+ t := st.demangleType(!inExpression)
+
+ if !inExpression {
+ st.templates = st.templates[:len(st.templates)-1]
+ }
+
+ return &Cast{To: t}, 1
+ } else if op, ok := operators[code]; ok {
+ return &Operator{Name: op.name}, op.args
+ } else {
+ st.failEarlier("unrecognized operator code", 2)
+ panic("not reached")
+ }
+}
+
+// <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
+// ::= Z <(function) encoding> E s [<discriminator>]
+// ::= Z <(function) encoding> E d [<parameter> number>] _ <entity name>
+func (st *state) localName() AST {
+ st.checkChar('Z')
+ fn := st.encoding(true)
+ if len(st.str) == 0 || st.str[0] != 'E' {
+ st.fail("expected E after local name")
+ }
+ st.advance(1)
+ if len(st.str) > 0 && st.str[0] == 's' {
+ st.advance(1)
+ var n AST = &Name{Name: "string literal"}
+ n = st.discriminator(n)
+ return &Qualified{Scope: fn, Name: n, LocalName: true}
+ } else {
+ num := -1
+ if len(st.str) > 0 && st.str[0] == 'd' {
+ // Default argument scope.
+ st.advance(1)
+ num = st.compactNumber()
+ }
+ var n AST = st.name()
+ n = st.discriminator(n)
+ if num >= 0 {
+ n = &DefaultArg{Num: num, Arg: n}
+ }
+ return &Qualified{Scope: fn, Name: n, LocalName: true}
+ }
+}
+
+// Parse a Java resource special-name.
+func (st *state) javaResource() AST {
+ off := st.off
+ ln := st.number()
+ if ln <= 1 {
+ st.failEarlier("java resource length less than 1", st.off-off)
+ }
+ if len(st.str) == 0 || st.str[0] != '_' {
+ st.fail("expected _ after number")
+ }
+ st.advance(1)
+ ln--
+ if len(st.str) < ln {
+ st.fail("not enough characters for java resource length")
+ }
+ str := st.str[:ln]
+ final := ""
+ st.advance(ln)
+ for i := 0; i < len(str); i++ {
+ if str[i] != '$' {
+ final += string(str[i])
+ } else {
+ if len(str) <= i+1 {
+ st.failEarlier("java resource escape at end of string", 1)
+ }
+ i++
+ r, ok := map[byte]string{
+ 'S': "/",
+ '_': ".",
+ '$': "$",
+ }[str[i]]
+ if !ok {
+ st.failEarlier("unrecognized java resource escape", ln-i-1)
+ }
+ final += r
+ }
+ }
+ return &Special{Prefix: "java resource ", Val: &Name{Name: final}}
+}
+
+// <special-name> ::= TV <type>
+// ::= TT <type>
+// ::= TI <type>
+// ::= TS <type>
+// ::= GV <(object) name>
+// ::= T <call-offset> <(base) encoding>
+// ::= Tc <call-offset> <call-offset> <(base) encoding>
+// Also g++ extensions:
+// ::= TC <type> <(offset) number> _ <(base) type>
+// ::= TF <type>
+// ::= TJ <type>
+// ::= GR <name>
+// ::= GA <encoding>
+// ::= Gr <resource name>
+// ::= GTt <encoding>
+// ::= GTn <encoding>
+func (st *state) specialName() AST {
+ if st.str[0] == 'T' {
+ st.advance(1)
+ if len(st.str) == 0 {
+ st.fail("expected special name code")
+ }
+ c := st.str[0]
+ st.advance(1)
+ switch c {
+ case 'V':
+ t := st.demangleType(false)
+ return &Special{Prefix: "vtable for ", Val: t}
+ case 'T':
+ t := st.demangleType(false)
+ return &Special{Prefix: "VTT for ", Val: t}
+ case 'I':
+ t := st.demangleType(false)
+ return &Special{Prefix: "typeinfo for ", Val: t}
+ case 'S':
+ t := st.demangleType(false)
+ return &Special{Prefix: "typeinfo name for ", Val: t}
+ case 'h':
+ st.callOffset('h')
+ v := st.encoding(true)
+ return &Special{Prefix: "non-virtual thunk to ", Val: v}
+ case 'v':
+ st.callOffset('v')
+ v := st.encoding(true)
+ return &Special{Prefix: "virtual thunk to ", Val: v}
+ case 'c':
+ st.callOffset(0)
+ st.callOffset(0)
+ v := st.encoding(true)
+ return &Special{Prefix: "covariant return thunk to ", Val: v}
+ case 'C':
+ derived := st.demangleType(false)
+ off := st.off
+ offset := st.number()
+ if offset < 0 {
+ st.failEarlier("expected positive offset", st.off-off)
+ }
+ if len(st.str) == 0 || st.str[0] != '_' {
+ st.fail("expected _ after number")
+ }
+ st.advance(1)
+ base := st.demangleType(false)
+ return &Special2{Prefix: "construction vtable for ", Val1: base, Middle: "-in-", Val2: derived}
+ case 'F':
+ t := st.demangleType(false)
+ return &Special{Prefix: "typeinfo fn for ", Val: t}
+ case 'J':
+ t := st.demangleType(false)
+ return &Special{Prefix: "java Class for ", Val: t}
+ case 'H':
+ n := st.name()
+ return &Special{Prefix: "TLS init function for ", Val: n}
+ case 'W':
+ n := st.name()
+ return &Special{Prefix: "TLS wrapper function for ", Val: n}
+ default:
+ st.fail("unrecognized special T name code")
+ panic("not reached")
+ }
+ } else {
+ st.checkChar('G')
+ if len(st.str) == 0 {
+ st.fail("expected special name code")
+ }
+ c := st.str[0]
+ st.advance(1)
+ switch c {
+ case 'V':
+ n := st.name()
+ 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}
+ case 'A':
+ v := st.encoding(true)
+ return &Special{Prefix: "hidden alias for ", Val: v}
+ case 'T':
+ if len(st.str) == 0 {
+ st.fail("expected special GT name code")
+ }
+ c := st.str[0]
+ st.advance(1)
+ v := st.encoding(true)
+ switch c {
+ case 'n':
+ return &Special{Prefix: "non-transaction clone for ", Val: v}
+ default:
+ // The proposal is that different
+ // letters stand for different types
+ // of transactional cloning. Treat
+ // them all the same for now.
+ fallthrough
+ case 't':
+ return &Special{Prefix: "transaction clone for ", Val: v}
+ }
+ case 'r':
+ return st.javaResource()
+ default:
+ st.fail("unrecognized special G name code")
+ panic("not reached")
+ }
+ }
+}
+
+// <call-offset> ::= h <nv-offset> _
+// ::= v <v-offset> _
+//
+// <nv-offset> ::= <(offset) number>
+//
+// <v-offset> ::= <(offset) number> _ <(virtual offset) number>
+//
+// The c parameter, if not 0, is a character we just read which is the
+// start of the <call-offset>.
+//
+// We don't display the offset information anywhere.
+func (st *state) callOffset(c byte) {
+ if c == 0 {
+ if len(st.str) == 0 {
+ st.fail("missing call offset")
+ }
+ c = st.str[0]
+ st.advance(1)
+ }
+ switch c {
+ case 'h':
+ st.number()
+ case 'v':
+ st.number()
+ if len(st.str) == 0 || st.str[0] != '_' {
+ st.fail("expected _ after number")
+ }
+ st.advance(1)
+ st.number()
+ default:
+ st.failEarlier("unrecognized call offset code", 1)
+ }
+ if len(st.str) == 0 || st.str[0] != '_' {
+ st.fail("expected _ after call offset")
+ }
+ st.advance(1)
+}
+
+// builtinTypes maps the type letter to the type name.
+var builtinTypes = map[byte]string{
+ 'a': "signed char",
+ 'b': "bool",
+ 'c': "char",
+ 'd': "double",
+ 'e': "long double",
+ 'f': "float",
+ 'g': "__float128",
+ 'h': "unsigned char",
+ 'i': "int",
+ 'j': "unsigned int",
+ 'l': "long",
+ 'm': "unsigned long",
+ 'n': "__int128",
+ 'o': "unsigned __int128",
+ 's': "short",
+ 't': "unsigned short",
+ 'v': "void",
+ 'w': "wchar_t",
+ 'x': "long long",
+ 'y': "unsigned long long",
+ 'z': "...",
+}
+
+// <type> ::= <builtin-type>
+// ::= <function-type>
+// ::= <class-enum-type>
+// ::= <array-type>
+// ::= <pointer-to-member-type>
+// ::= <template-param>
+// ::= <template-template-param> <template-args>
+// ::= <substitution>
+// ::= <CV-qualifiers> <type>
+// ::= P <type>
+// ::= R <type>
+// ::= O <type> (C++0x)
+// ::= C <type>
+// ::= G <type>
+// ::= U <source-name> <type>
+//
+// <builtin-type> ::= various one letter codes
+// ::= u <source-name>
+func (st *state) demangleType(isCast bool) AST {
+ if len(st.str) == 0 {
+ st.fail("expected type")
+ }
+
+ addSubst := true
+
+ q := st.cvQualifiers()
+ if len(q) > 0 {
+ if len(st.str) == 0 {
+ st.fail("expected type")
+ }
+
+ // CV-qualifiers before a function type apply to
+ // 'this', so avoid adding the unqualified function
+ // type to the substitution list.
+ if st.str[0] == 'F' {
+ addSubst = false
+ }
+ }
+
+ var ret AST
+
+ // Use correct substitution for a template parameter.
+ var sub AST
+
+ if btype, ok := builtinTypes[st.str[0]]; ok {
+ ret = &BuiltinType{Name: btype}
+ st.advance(1)
+ if len(q) > 0 {
+ ret = &TypeWithQualifiers{Base: ret, Qualifiers: q}
+ st.subs.add(ret)
+ }
+ return ret
+ }
+ c := st.str[0]
+ switch c {
+ case 'u':
+ st.advance(1)
+ ret = st.sourceName()
+ case 'F':
+ ret = st.functionType()
+ case 'N', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ ret = st.name()
+ case 'A':
+ ret = st.arrayType(isCast)
+ case 'M':
+ ret = st.pointerToMemberType(isCast)
+ case 'T':
+ ret = st.templateParam()
+ if len(st.str) > 0 && st.str[0] == 'I' {
+ // See the function comment to explain this.
+ if !isCast {
+ st.subs.add(ret)
+ args := st.templateArgs()
+ ret = &Template{Name: ret, Args: args}
+ } else {
+ ret = st.demangleCastTemplateArgs(ret, true)
+ }
+ }
+ case 'S':
+ // If this is a special substitution, then it
+ // is the start of <class-enum-type>.
+ var c2 byte
+ if len(st.str) > 1 {
+ c2 = st.str[1]
+ }
+ if isDigit(c2) || c2 == '_' || isUpper(c2) {
+ ret = st.substitution(false)
+ if len(st.str) == 0 || st.str[0] != 'I' {
+ addSubst = false
+ } else {
+ // See the function comment to explain this.
+ if _, ok := ret.(*TemplateParam); !ok || !isCast {
+ args := st.templateArgs()
+ ret = &Template{Name: ret, Args: args}
+ } else {
+ next := st.demangleCastTemplateArgs(ret, false)
+ if next == ret {
+ addSubst = false
+ }
+ ret = next
+ }
+ }
+ } else {
+ ret = st.name()
+ // This substitution is not itself a
+ // substitution candidate, unless template
+ // arguments were added.
+ if ret == subAST[c2] || ret == verboseAST[c2] {
+ addSubst = false
+ }
+ }
+ case 'O', 'P', 'R', 'C', 'G':
+ st.advance(1)
+ t := st.demangleType(isCast)
+ switch c {
+ case 'O':
+ ret = &RvalueReferenceType{Base: t}
+ case 'P':
+ ret = &PointerType{Base: t}
+ case 'R':
+ ret = &ReferenceType{Base: t}
+ case 'C':
+ ret = &ComplexType{Base: t}
+ case 'G':
+ ret = &ImaginaryType{Base: t}
+ }
+ case 'U':
+ if len(st.str) < 2 {
+ st.fail("expected source name or unnamed type")
+ }
+ switch st.str[1] {
+ case 'l':
+ ret = st.closureTypeName()
+ addSubst = false
+ case 't':
+ ret = st.unnamedTypeName()
+ addSubst = false
+ default:
+ st.advance(1)
+ n := st.sourceName()
+ if len(st.str) > 0 && st.str[0] == 'I' {
+ args := st.templateArgs()
+ n = &Template{Name: n, Args: args}
+ }
+ t := st.demangleType(isCast)
+ ret = &VendorQualifier{Qualifier: n, Type: t}
+ }
+ case 'D':
+ st.advance(1)
+ if len(st.str) == 0 {
+ st.fail("expected D code for type")
+ }
+ addSubst = false
+ c2 := st.str[0]
+ st.advance(1)
+ switch c2 {
+ case 'T', 't':
+ // decltype(expression)
+ ret = st.expression()
+ if len(st.str) == 0 || st.str[0] != 'E' {
+ st.fail("expected E after expression in type")
+ }
+ st.advance(1)
+ ret = &Decltype{Expr: ret}
+ addSubst = true
+
+ case 'p':
+ t := st.demangleType(isCast)
+ pack := st.findArgumentPack(t)
+ ret = &PackExpansion{Base: t, Pack: pack}
+ addSubst = true
+
+ case 'a':
+ ret = &Name{Name: "auto"}
+
+ case 'f':
+ ret = &BuiltinType{Name: "decimal32"}
+ case 'd':
+ ret = &BuiltinType{Name: "decimal64"}
+ case 'e':
+ ret = &BuiltinType{Name: "decimal128"}
+ case 'h':
+ ret = &BuiltinType{Name: "half"}
+ case 's':
+ ret = &BuiltinType{Name: "char16_t"}
+ case 'i':
+ ret = &BuiltinType{Name: "char32_t"}
+ case 'n':
+ ret = &BuiltinType{Name: "decltype(nullptr)"}
+
+ case 'F':
+ accum := false
+ if len(st.str) > 0 && isDigit(st.str[0]) {
+ accum = true
+ // We don't care about the bits.
+ _ = st.number()
+ }
+ base := st.demangleType(isCast)
+ if len(st.str) > 0 && isDigit(st.str[0]) {
+ // We don't care about the bits.
+ st.number()
+ }
+ sat := false
+ if len(st.str) > 0 {
+ if st.str[0] == 's' {
+ sat = true
+ }
+ st.advance(1)
+ }
+ ret = &FixedType{Base: base, Accum: accum, Sat: sat}
+
+ case 'v':
+ ret = st.vectorType(isCast)
+ addSubst = true
+
+ default:
+ st.fail("unrecognized D code in type")
+ }
+
+ default:
+ st.fail("unrecognized type code")
+ }
+
+ if addSubst {
+ if sub != nil {
+ st.subs.add(sub)
+ } else {
+ st.subs.add(ret)
+ }
+ }
+
+ if len(q) > 0 {
+ if _, ok := ret.(*FunctionType); ok {
+ ret = &MethodWithQualifiers{Method: ret, Qualifiers: q, RefQualifier: ""}
+ } else if mwq, ok := ret.(*MethodWithQualifiers); ok {
+ // Merge adjacent qualifiers. This case
+ // happens with a function with a trailing
+ // ref-qualifier.
+ mwq.Qualifiers = mergeQualifiers(q, mwq.Qualifiers)
+ } else {
+ // Merge adjacent qualifiers. This case
+ // happens with multi-dimensional array types.
+ if qsub, ok := ret.(*TypeWithQualifiers); ok {
+ q = mergeQualifiers(q, qsub.Qualifiers)
+ ret = qsub.Base
+ }
+ ret = &TypeWithQualifiers{Base: ret, Qualifiers: q}
+ }
+ st.subs.add(ret)
+ }
+
+ return ret
+}
+
+// demangleCastTemplateArgs is for a rather hideous parse. When we
+// see a template-param followed by a template-args, we need to decide
+// whether we have a template-param or a template-template-param.
+// Normally it is template-template-param, meaning that we pick up the
+// template arguments here. But, if we are parsing the type for a
+// cast operator, then the only way this can be template-template-param
+// is if there is another set of template-args immediately after this
+// set. That would look like this:
+//
+// <nested-name>
+// -> <template-prefix> <template-args>
+// -> <prefix> <template-unqualified-name> <template-args>
+// -> <unqualified-name> <template-unqualified-name> <template-args>
+// -> <source-name> <template-unqualified-name> <template-args>
+// -> <source-name> <operator-name> <template-args>
+// -> <source-name> cv <type> <template-args>
+// -> <source-name> cv <template-template-param> <template-args> <template-args>
+//
+// Otherwise, we have this derivation:
+//
+// <nested-name>
+// -> <template-prefix> <template-args>
+// -> <prefix> <template-unqualified-name> <template-args>
+// -> <unqualified-name> <template-unqualified-name> <template-args>
+// -> <source-name> <template-unqualified-name> <template-args>
+// -> <source-name> <operator-name> <template-args>
+// -> <source-name> cv <type> <template-args>
+// -> <source-name> cv <template-param> <template-args>
+//
+// in which the template-args are actually part of the prefix. For
+// the special case where this arises, demangleType is called with
+// isCast as true. This function is then responsible for checking
+// whether we see <template-param> <template-args> but there is not
+// another following <template-args>. In that case, we reset the
+// parse and just return the <template-param>.
+func (st *state) demangleCastTemplateArgs(tp AST, addSubst bool) AST {
+ save := st.copy()
+
+ var args []AST
+ failed := false
+ func() {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(demangleErr); ok {
+ failed = true
+ } else {
+ panic(r)
+ }
+ }
+ }()
+
+ args = st.templateArgs()
+ }()
+
+ if !failed && len(st.str) > 0 && st.str[0] == 'I' {
+ if addSubst {
+ st.subs.add(tp)
+ }
+ return &Template{Name: tp, Args: args}
+ }
+ // Reset back to before we started reading the template arguments.
+ // They will be read again by st.prefix.
+ *st = *save
+ return tp
+}
+
+// mergeQualifiers merges two qualifer lists into one.
+func mergeQualifiers(q1, q2 Qualifiers) Qualifiers {
+ m := make(map[string]bool)
+ for _, qual := range q1 {
+ m[qual] = true
+ }
+ for _, qual := range q2 {
+ if !m[qual] {
+ q1 = append(q1, qual)
+ m[qual] = true
+ }
+ }
+ return q1
+}
+
+// qualifiers maps from the character used in the mangled name to the
+// string to print.
+var qualifiers = map[byte]string{
+ 'r': "restrict",
+ 'V': "volatile",
+ 'K': "const",
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+func (st *state) cvQualifiers() Qualifiers {
+ var q Qualifiers
+ for len(st.str) > 0 {
+ if qv, ok := qualifiers[st.str[0]]; ok {
+ q = append([]string{qv}, q...)
+ st.advance(1)
+ } else if len(st.str) > 1 && st.str[:2] == "Dx" {
+ q = append([]string{"transaction_safe"}, q...)
+ st.advance(2)
+ } else {
+ break
+ }
+ }
+ return q
+}
+
+// <ref-qualifier> ::= R
+// ::= O
+func (st *state) refQualifier() string {
+ if len(st.str) > 0 {
+ switch st.str[0] {
+ case 'R':
+ st.advance(1)
+ return "&"
+ case 'O':
+ st.advance(1)
+ return "&&"
+ }
+ }
+ return ""
+}
+
+// <type>+
+func (st *state) parmlist() []AST {
+ var ret []AST
+ for {
+ if len(st.str) < 1 {
+ break
+ }
+ if st.str[0] == 'E' || st.str[0] == '.' {
+ break
+ }
+ if (st.str[0] == 'R' || st.str[0] == 'O') && len(st.str) > 1 && st.str[1] == 'E' {
+ // This is a function ref-qualifier.
+ break
+ }
+ ptype := st.demangleType(false)
+ ret = append(ret, ptype)
+ }
+
+ // There should always be at least one type. A function that
+ // takes no arguments will have a single parameter type
+ // "void".
+ if len(ret) == 0 {
+ st.fail("expected at least one type in type list")
+ }
+
+ // Omit a single parameter type void.
+ if len(ret) == 1 {
+ if bt, ok := ret[0].(*BuiltinType); ok && bt.Name == "void" {
+ ret = nil
+ }
+ }
+
+ return ret
+}
+
+// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+func (st *state) functionType() AST {
+ st.checkChar('F')
+ if len(st.str) > 0 && st.str[0] == 'Y' {
+ // Function has C linkage. We don't print this.
+ st.advance(1)
+ }
+ ret := st.bareFunctionType(true)
+ r := st.refQualifier()
+ if r != "" {
+ ret = &MethodWithQualifiers{Method: ret, Qualifiers: nil, RefQualifier: r}
+ }
+ if len(st.str) == 0 || st.str[0] != 'E' {
+ st.fail("expected E after function type")
+ }
+ st.advance(1)
+ return ret
+}
+
+// <bare-function-type> ::= [J]<type>+
+func (st *state) bareFunctionType(hasReturnType bool) AST {
+ if len(st.str) > 0 && st.str[0] == 'J' {
+ hasReturnType = true
+ st.advance(1)
+ }
+ var returnType AST
+ if hasReturnType {
+ returnType = st.demangleType(false)
+ }
+ types := st.parmlist()
+ return &FunctionType{Return: returnType, Args: types}
+}
+
+// <array-type> ::= A <(positive dimension) number> _ <(element) type>
+// ::= A [<(dimension) expression>] _ <(element) type>
+func (st *state) arrayType(isCast bool) AST {
+ st.checkChar('A')
+
+ if len(st.str) == 0 {
+ st.fail("missing array dimension")
+ }
+
+ var dim AST
+ if st.str[0] == '_' {
+ dim = &Name{Name: ""}
+ } else if isDigit(st.str[0]) {
+ i := 1
+ for len(st.str) > i && isDigit(st.str[i]) {
+ i++
+ }
+ dim = &Name{Name: st.str[:i]}
+ st.advance(i)
+ } else {
+ dim = st.expression()
+ }
+
+ if len(st.str) == 0 || st.str[0] != '_' {
+ st.fail("expected _ after dimension")
+ }
+ st.advance(1)
+
+ t := st.demangleType(isCast)
+
+ arr := &ArrayType{Dimension: dim, Element: t}
+
+ // Qualifiers on the element of an array type go on the whole
+ // array type.
+ if q, ok := arr.Element.(*TypeWithQualifiers); ok {
+ return &TypeWithQualifiers{Base: &ArrayType{Dimension: dim, Element: q.Base}, Qualifiers: q.Qualifiers}
+ }
+
+ return arr
+}
+
+// <vector-type> ::= Dv <number> _ <type>
+// ::= Dv _ <expression> _ <type>
+func (st *state) vectorType(isCast bool) AST {
+ if len(st.str) == 0 {
+ st.fail("expected vector dimension")
+ }
+
+ var dim AST
+ if st.str[0] == '_' {
+ st.advance(1)
+ dim = st.expression()
+ } else {
+ num := st.number()
+ dim = &Name{Name: fmt.Sprintf("%d", num)}
+ }
+
+ if len(st.str) == 0 || st.str[0] != '_' {
+ st.fail("expected _ after vector dimension")
+ }
+ st.advance(1)
+
+ t := st.demangleType(isCast)
+
+ return &VectorType{Dimension: dim, Base: t}
+}
+
+// <pointer-to-member-type> ::= M <(class) type> <(member) type>
+func (st *state) pointerToMemberType(isCast bool) AST {
+ st.checkChar('M')
+ cl := st.demangleType(false)
+
+ // The ABI says, "The type of a non-static member function is
+ // considered to be different, for the purposes of
+ // substitution, from the type of a namespace-scope or static
+ // member function whose type appears similar. The types of
+ // two non-static member functions are considered to be
+ // different, for the purposes of substitution, if the
+ // functions are members of different classes. In other words,
+ // for the purposes of substitution, the class of which the
+ // function is a member is considered part of the type of
+ // function."
+ //
+ // For a pointer to member function, this call to demangleType
+ // will end up adding a (possibly qualified) non-member
+ // function type to the substitution table, which is not
+ // correct; however, the member function type will never be
+ // used in a substitution, so putting the wrong type in the
+ // substitution table is harmless.
+ mem := st.demangleType(isCast)
+ return &PtrMem{Class: cl, Member: mem}
+}
+
+// <non-negative number> _ */
+func (st *state) compactNumber() int {
+ if len(st.str) == 0 {
+ st.fail("missing index")
+ }
+ if st.str[0] == '_' {
+ st.advance(1)
+ return 0
+ } else if st.str[0] == 'n' {
+ st.fail("unexpected negative number")
+ }
+ n := st.number()
+ if len(st.str) == 0 || st.str[0] != '_' {
+ st.fail("missing underscore after number")
+ }
+ st.advance(1)
+ return n + 1
+}
+
+// <template-param> ::= T_
+// ::= T <(parameter-2 non-negative) number> _
+//
+// When a template parameter is a substitution candidate, any
+// reference to that substitution refers to the template parameter
+// with the same index in the currently active template, not to
+// 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.fail("template parameter not in scope of template")
+ }
+ off := st.off
+
+ st.checkChar('T')
+ n := st.compactNumber()
+
+ template := st.templates[len(st.templates)-1]
+
+ if template == nil {
+ // We are parsing a cast operator. If the cast is
+ // itself a template, then this is a forward
+ // reference. Fill it in later.
+ return &TemplateParam{Index: n, Template: nil}
+ }
+
+ if n >= len(template.Args) {
+ st.failEarlier(fmt.Sprintf("template index out of range (%d >= %d)", n, len(template.Args)), st.off-off)
+ }
+
+ return &TemplateParam{Index: n, Template: template}
+}
+
+// setTemplate sets the Template field of any TemplateParam's in a.
+// This handles the forward referencing template parameters found in
+// cast operators.
+func (st *state) setTemplate(a AST, tmpl *Template) {
+ var seen []AST
+ a.Traverse(func(a AST) bool {
+ switch a := a.(type) {
+ case *TemplateParam:
+ if a.Template != nil {
+ if tmpl != nil {
+ st.fail("duplicate template parameters")
+ }
+ return false
+ }
+ if tmpl == nil {
+ st.fail("cast template parameter not in scope of template")
+ }
+ if a.Index >= len(tmpl.Args) {
+ st.fail(fmt.Sprintf("cast template index out of range (%d >= %d)", a.Index, len(tmpl.Args)))
+ }
+ a.Template = tmpl
+ return false
+ default:
+ for _, v := range seen {
+ if v == a {
+ return false
+ }
+ }
+ seen = append(seen, a)
+ return true
+ }
+ })
+}
+
+// clearTemplateArgs gives an error for any unset Template field in
+// args. This handles erroneous cases where a cast operator with a
+// forward referenced template is in the scope of another cast
+// operator.
+func (st *state) clearTemplateArgs(args []AST) {
+ for _, a := range args {
+ st.setTemplate(a, nil)
+ }
+}
+
+// <template-args> ::= I <template-arg>+ E
+func (st *state) templateArgs() []AST {
+ if len(st.str) == 0 || (st.str[0] != 'I' && st.str[0] != 'J') {
+ panic("internal error")
+ }
+ st.advance(1)
+
+ var ret []AST
+ for len(st.str) == 0 || st.str[0] != 'E' {
+ arg := st.templateArg()
+ ret = append(ret, arg)
+ }
+ st.advance(1)
+ return ret
+}
+
+// <template-arg> ::= <type>
+// ::= X <expression> E
+// ::= <expr-primary>
+func (st *state) templateArg() AST {
+ if len(st.str) == 0 {
+ st.fail("missing template argument")
+ }
+ switch st.str[0] {
+ case 'X':
+ st.advance(1)
+ expr := st.expression()
+ if len(st.str) == 0 || st.str[0] != 'E' {
+ st.fail("missing end of expression")
+ }
+ st.advance(1)
+ return expr
+
+ case 'L':
+ return st.exprPrimary()
+
+ case 'I', 'J':
+ args := st.templateArgs()
+ return &ArgumentPack{Args: args}
+
+ default:
+ return st.demangleType(false)
+ }
+}
+
+// exprList parses a sequence of expressions up to a terminating character.
+func (st *state) exprList(stop byte) AST {
+ if len(st.str) > 0 && st.str[0] == stop {
+ st.advance(1)
+ return &ExprList{Exprs: nil}
+ }
+
+ var exprs []AST
+ for {
+ e := st.expression()
+ exprs = append(exprs, e)
+ if len(st.str) > 0 && st.str[0] == stop {
+ st.advance(1)
+ break
+ }
+ }
+ return &ExprList{Exprs: exprs}
+}
+
+// <expression> ::= <(unary) operator-name> <expression>
+// ::= <(binary) operator-name> <expression> <expression>
+// ::= <(trinary) operator-name> <expression> <expression> <expression>
+// ::= cl <expression>+ E
+// ::= st <type>
+// ::= <template-param>
+// ::= sr <type> <unqualified-name>
+// ::= sr <type> <unqualified-name> <template-args>
+// ::= <expr-primary>
+func (st *state) expression() AST {
+ if len(st.str) == 0 {
+ st.fail("expected expression")
+ }
+ if st.str[0] == 'L' {
+ 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] == 'r' {
+ st.advance(2)
+ if len(st.str) == 0 {
+ st.fail("expected unresolved type")
+ }
+ switch st.str[0] {
+ case 'T', 'D', 'S':
+ t := st.demangleType(false)
+ n := st.baseUnresolvedName()
+ n = &Qualified{Scope: t, Name: n, LocalName: false}
+ if len(st.str) > 0 && st.str[0] == 'I' {
+ args := st.templateArgs()
+ n = &Template{Name: n, Args: args}
+ }
+ return n
+ default:
+ var s AST
+ if st.str[0] == 'N' {
+ st.advance(1)
+ s = st.demangleType(false)
+ }
+ for len(st.str) == 0 || st.str[0] != 'E' {
+ // GCC does not seem to follow the ABI here.
+ // It can emit type/name without an 'E'.
+ if s != nil && len(st.str) > 0 && !isDigit(st.str[0]) {
+ if q, ok := s.(*Qualified); ok {
+ a := q.Scope
+ if t, ok := a.(*Template); ok {
+ st.subs.add(t.Name)
+ st.subs.add(t)
+ } else {
+ st.subs.add(a)
+ }
+ return s
+ }
+ }
+ n := st.sourceName()
+ if len(st.str) > 0 && st.str[0] == 'I' {
+ st.subs.add(n)
+ args := st.templateArgs()
+ n = &Template{Name: n, Args: args}
+ }
+ if s == nil {
+ s = n
+ } else {
+ s = &Qualified{Scope: s, Name: n, LocalName: false}
+ }
+ st.subs.add(s)
+ }
+ if s == nil {
+ st.fail("missing scope in unresolved name")
+ }
+ st.advance(1)
+ n := st.baseUnresolvedName()
+ return &Qualified{Scope: s, Name: n, LocalName: false}
+ }
+ } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'p' {
+ st.advance(2)
+ e := st.expression()
+ pack := st.findArgumentPack(e)
+ return &PackExpansion{Base: e, Pack: pack}
+ } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'Z' {
+ st.advance(2)
+ off := st.off
+ e := st.expression()
+ ap := st.findArgumentPack(e)
+ if ap == nil {
+ st.failEarlier("missing argument pack", st.off-off)
+ }
+ return &SizeofPack{Pack: ap}
+ } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'P' {
+ st.advance(2)
+ var args []AST
+ for len(st.str) == 0 || st.str[0] != 'E' {
+ arg := st.templateArg()
+ args = append(args, arg)
+ }
+ st.advance(1)
+ return &SizeofArgs{Args: args}
+ } else if st.str[0] == 'f' && len(st.str) > 1 && st.str[1] == 'p' {
+ st.advance(2)
+ if len(st.str) > 0 && st.str[0] == 'T' {
+ st.advance(1)
+ return &FunctionParam{Index: 0}
+ } else {
+ index := st.compactNumber()
+ return &FunctionParam{Index: index + 1}
+ }
+ } 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.
+ st.advance(2)
+ }
+ n, _ := st.unqualifiedName()
+ if len(st.str) > 0 && st.str[0] == 'I' {
+ args := st.templateArgs()
+ n = &Template{Name: n, Args: args}
+ }
+ return n
+ } else if (st.str[0] == 'i' || st.str[0] == 't') && len(st.str) > 1 && st.str[1] == 'l' {
+ // Brace-enclosed initializer list.
+ c := st.str[0]
+ st.advance(2)
+ var t AST
+ if c == 't' {
+ t = st.demangleType(false)
+ }
+ exprs := st.exprList('E')
+ return &InitializerList{Type: t, Exprs: exprs}
+ } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 't' {
+ o, _ := st.operatorName(true)
+ t := st.demangleType(false)
+ return &Unary{Op: o, Expr: t, Suffix: false, SizeofType: true}
+ } else {
+ if len(st.str) < 2 {
+ st.fail("missing operator code")
+ }
+ code := st.str[:2]
+ o, args := st.operatorName(true)
+ switch args {
+ case 0:
+ return &Nullary{Op: o}
+
+ case 1:
+ suffix := false
+ if code == "pp" || code == "mm" {
+ if len(st.str) > 0 && st.str[0] == '_' {
+ st.advance(1)
+ } else {
+ suffix = true
+ }
+ }
+ var operand AST
+ if _, ok := o.(*Cast); ok && len(st.str) > 0 && st.str[0] == '_' {
+ st.advance(1)
+ operand = st.exprList('E')
+ } else {
+ operand = st.expression()
+ }
+ return &Unary{Op: o, Expr: operand, Suffix: suffix, SizeofType: false}
+
+ case 2:
+ var left, right AST
+ if code == "sc" || code == "dc" || code == "cc" || code == "rc" {
+ left = st.demangleType(false)
+ } else if code[0] == 'f' {
+ left, _ = st.operatorName(true)
+ right = st.expression()
+ return &Fold{Left: code[1] == 'l', Op: left, Arg1: right, Arg2: nil}
+ } else {
+ left = st.expression()
+ }
+ if code == "cl" {
+ right = st.exprList('E')
+ } else if code == "dt" || code == "pt" {
+ right, _ = st.unqualifiedName()
+ if len(st.str) > 0 && st.str[0] == 'I' {
+ args := st.templateArgs()
+ right = &Template{Name: right, Args: args}
+ }
+ } else {
+ right = st.expression()
+ }
+ return &Binary{Op: o, Left: left, Right: right}
+
+ case 3:
+ if code[0] == 'n' {
+ if code[1] != 'w' && code[1] != 'a' {
+ panic("internal error")
+ }
+ place := st.exprList('_')
+ if place.(*ExprList).Exprs == nil {
+ place = nil
+ }
+ t := st.demangleType(false)
+ var ini AST
+ if len(st.str) > 0 && st.str[0] == 'E' {
+ st.advance(1)
+ } else if len(st.str) > 1 && st.str[0] == 'p' && st.str[1] == 'i' {
+ // Parenthesized initializer.
+ st.advance(2)
+ ini = st.exprList('E')
+ } else if len(st.str) > 1 && st.str[0] == 'i' && st.str[1] == 'l' {
+ // Initializer list.
+ ini = st.expression()
+ } else {
+ st.fail("unrecognized new initializer")
+ }
+ return &New{Op: o, Place: place, Type: t, Init: ini}
+ } else if code[0] == 'f' {
+ first, _ := st.operatorName(true)
+ second := st.expression()
+ third := st.expression()
+ return &Fold{Left: code[1] == 'L', Op: first, Arg1: second, Arg2: third}
+ } else {
+ first := st.expression()
+ second := st.expression()
+ third := st.expression()
+ return &Trinary{Op: o, First: first, Second: second, Third: third}
+ }
+
+ default:
+ st.fail(fmt.Sprintf("unsupported number of operator arguments: %d", args))
+ panic("not reached")
+ }
+ }
+}
+
+// <base-unresolved-name> ::= <simple-id>
+// ::= on <operator-name>
+// ::= on <operator-name> <template-args>
+// ::= dn <destructor-name>
+//
+//<simple-id> ::= <source-name> [ <template-args> ]
+func (st *state) baseUnresolvedName() AST {
+ var n AST
+ if len(st.str) >= 2 && st.str[:2] == "on" {
+ st.advance(2)
+ n, _ = st.operatorName(true)
+ } else if len(st.str) >= 2 && st.str[:2] == "dn" {
+ st.advance(2)
+ if len(st.str) > 0 && isDigit(st.str[0]) {
+ n = st.sourceName()
+ } else {
+ n = st.demangleType(false)
+ }
+ n = &Destructor{Name: n}
+ } else if len(st.str) > 0 && isDigit(st.str[0]) {
+ n = st.sourceName()
+ } else {
+ // GCC seems to not follow the ABI here: it can have
+ // an operator name without on.
+ // See https://gcc.gnu.org/PR70182.
+ n, _ = st.operatorName(true)
+ }
+ if len(st.str) > 0 && st.str[0] == 'I' {
+ args := st.templateArgs()
+ n = &Template{Name: n, Args: args}
+ }
+ return n
+}
+
+// <expr-primary> ::= L <type> <(value) number> E
+// ::= L <type> <(value) float> E
+// ::= L <mangled-name> E
+func (st *state) exprPrimary() AST {
+ st.checkChar('L')
+ if len(st.str) == 0 {
+ st.fail("expected primary expression")
+
+ }
+
+ // Check for 'Z' here because g++ incorrectly omitted the
+ // underscore until -fabi-version=3.
+ var ret AST
+ if st.str[0] == '_' || st.str[0] == 'Z' {
+ if st.str[0] == '_' {
+ st.advance(1)
+ }
+ if len(st.str) == 0 || st.str[0] != 'Z' {
+ st.fail("expected mangled name")
+ }
+ st.advance(1)
+ ret = st.encoding(true)
+ } else {
+ t := st.demangleType(false)
+
+ neg := false
+ if len(st.str) > 0 && st.str[0] == 'n' {
+ neg = true
+ st.advance(1)
+ }
+ i := 0
+ for len(st.str) > i && st.str[i] != 'E' {
+ i++
+ }
+ val := st.str[:i]
+ st.advance(i)
+ ret = &Literal{Type: t, Val: val, Neg: neg}
+ }
+ if len(st.str) == 0 || st.str[0] != 'E' {
+ st.fail("expected E after literal")
+ }
+ st.advance(1)
+ return ret
+}
+
+// <discriminator> ::= _ <(non-negative) number>
+func (st *state) discriminator(a AST) AST {
+ if len(st.str) == 0 || st.str[0] != '_' {
+ return a
+ }
+ off := st.off
+ st.advance(1)
+ d := st.number()
+ if d < 0 {
+ st.failEarlier("invalid negative discriminator", st.off-off)
+ }
+ // We don't currently print out the discriminator, so we don't
+ // save it.
+ return a
+}
+
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+func (st *state) closureTypeName() AST {
+ st.checkChar('U')
+ st.checkChar('l')
+ types := st.parmlist()
+ if len(st.str) == 0 || st.str[0] != 'E' {
+ st.fail("expected E after closure type name")
+ }
+ st.advance(1)
+ num := st.compactNumber()
+ ret := &Closure{Types: types, Num: num}
+ st.subs.add(ret)
+ return ret
+}
+
+// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
+func (st *state) unnamedTypeName() AST {
+ st.checkChar('U')
+ st.checkChar('t')
+ num := st.compactNumber()
+ ret := &UnnamedType{Num: num}
+ st.subs.add(ret)
+ return ret
+}
+
+// Recognize a clone suffix. These are not part of the mangling API,
+// but are added by GCC when cloning functions.
+func (st *state) cloneSuffix(a AST) AST {
+ i := 0
+ if len(st.str) > 1 && st.str[0] == '.' && (isLower(st.str[1]) || st.str[1] == '_') {
+ i += 2
+ for len(st.str) > i && (isLower(st.str[i]) || st.str[i] == '_') {
+ i++
+ }
+ }
+ for len(st.str) > i+1 && st.str[i] == '.' && isDigit(st.str[i+1]) {
+ i += 2
+ for len(st.str) > i && isDigit(st.str[i]) {
+ i++
+ }
+ }
+ suffix := st.str[:i]
+ st.advance(i)
+ return &Clone{Base: a, Suffix: suffix}
+}
+
+// substitutions is the list of substitution candidates that may
+// appear later in the string.
+type substitutions []AST
+
+// add adds a new substitution candidate.
+func (subs *substitutions) add(a AST) {
+ *subs = append(*subs, a)
+}
+
+// subAST maps standard substitution codes to the corresponding AST.
+var subAST = map[byte]AST{
+ 't': &Name{Name: "std"},
+ 'a': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}},
+ 'b': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}},
+ 's': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "string"}},
+ 'i': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "istream"}},
+ 'o': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "ostream"}},
+ 'd': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "iostream"}},
+}
+
+// verboseAST maps standard substitution codes to the long form of the
+// corresponding AST. We use this when the Verbose option is used, to
+// match the standard demangler.
+var verboseAST = map[byte]AST{
+ 't': &Name{Name: "std"},
+ 'a': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}},
+ 'b': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}},
+
+ // std::basic_string<char, std::char_traits<char>, std::allocator<char> >
+ 's': &Template{
+ Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}},
+ Args: []AST{
+ &BuiltinType{Name: "char"},
+ &Template{
+ Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
+ Args: []AST{&BuiltinType{Name: "char"}}},
+ &Template{
+ Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}},
+ Args: []AST{&BuiltinType{Name: "char"}}}}},
+ // std::basic_istream<char, std::char_traits<char> >
+ 'i': &Template{
+ Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_istream"}},
+ Args: []AST{
+ &BuiltinType{Name: "char"},
+ &Template{
+ Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
+ Args: []AST{&BuiltinType{Name: "char"}}}}},
+ // std::basic_ostream<char, std::char_traits<char> >
+ 'o': &Template{
+ Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_ostream"}},
+ Args: []AST{
+ &BuiltinType{Name: "char"},
+ &Template{
+ Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
+ Args: []AST{&BuiltinType{Name: "char"}}}}},
+ // std::basic_iostream<char, std::char_traits<char> >
+ 'd': &Template{
+ Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_iostream"}},
+ Args: []AST{
+ &BuiltinType{Name: "char"},
+ &Template{
+ Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
+ Args: []AST{&BuiltinType{Name: "char"}}}}},
+}
+
+// <substitution> ::= S <seq-id> _
+// ::= S_
+// ::= St
+// ::= Sa
+// ::= Sb
+// ::= Ss
+// ::= Si
+// ::= So
+// ::= Sd
+func (st *state) substitution(forPrefix bool) AST {
+ st.checkChar('S')
+ if len(st.str) == 0 {
+ st.fail("missing substitution index")
+ }
+ c := st.str[0]
+ st.advance(1)
+ dec := 1
+ 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++
+ }
+
+ if id >= len(st.subs) {
+ st.failEarlier(fmt.Sprintf("substitution index out of range (%d >= %d)", id, len(st.subs)), dec)
+ }
+
+ ret := st.subs[id]
+
+ // We need to update any references to template
+ // parameters to refer to the currently active
+ // template.
+ copy := func(a AST) AST {
+ tp, ok := a.(*TemplateParam)
+ if !ok {
+ return nil
+ }
+ if len(st.templates) == 0 {
+ st.failEarlier("substituted template parameter not in scope of template", dec)
+ }
+ template := st.templates[len(st.templates)-1]
+ if template == nil {
+ // This template parameter is within
+ // the scope of a cast operator.
+ return &TemplateParam{Index: tp.Index, Template: nil}
+ }
+
+ if tp.Index >= len(template.Args) {
+ st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", tp.Index, len(template.Args)), dec)
+ }
+
+ return &TemplateParam{Index: tp.Index, Template: template}
+ }
+ var seen []AST
+ skip := func(a AST) bool {
+ if _, ok := a.(*Typed); ok {
+ return true
+ }
+ for _, v := range seen {
+ if v == a {
+ return true
+ }
+ }
+ seen = append(seen, a)
+ return false
+ }
+ if c := ret.Copy(copy, skip); c != nil {
+ return c
+ }
+
+ return ret
+ } else {
+ m := subAST
+ if st.verbose {
+ m = verboseAST
+ }
+ // For compatibility with the standard demangler, use
+ // a longer name for a constructor or destructor.
+ if forPrefix && len(st.str) > 0 && (st.str[0] == 'C' || st.str[0] == 'D') {
+ m = verboseAST
+ }
+ a, ok := m[c]
+ if !ok {
+ st.failEarlier("unrecognized substitution code", 1)
+ }
+
+ if len(st.str) > 0 && st.str[0] == 'B' {
+ a = st.taggedName(a)
+ }
+
+ return a
+ }
+}
+
+// isDigit returns whetner c is a digit for demangling purposes.
+func isDigit(c byte) bool {
+ return c >= '0' && c <= '9'
+}
+
+// isUpper returns whether c is an upper case letter for demangling purposes.
+func isUpper(c byte) bool {
+ return c >= 'A' && c <= 'Z'
+}
+
+// isLower returns whether c is a lower case letter for demangling purposes.
+func isLower(c byte) bool {
+ return c >= 'a' && c <= 'z'
+}
+
+// simplify replaces template parameters with their expansions, and
+// merges qualifiers.
+func simplify(a AST) AST {
+ var seen []AST
+ skip := func(a AST) bool {
+ for _, v := range seen {
+ if v == a {
+ return true
+ }
+ }
+ seen = append(seen, a)
+ return false
+ }
+ if r := a.Copy(simplifyOne, skip); r != nil {
+ return r
+ }
+ return a
+}
+
+// simplifyOne simplifies a single AST. It returns nil if there is
+// nothing to do.
+func simplifyOne(a AST) AST {
+ switch a := a.(type) {
+ case *TemplateParam:
+ if a.Template != nil && a.Index < len(a.Template.Args) {
+ return a.Template.Args[a.Index]
+ }
+ case *MethodWithQualifiers:
+ if m, ok := a.Method.(*MethodWithQualifiers); ok {
+ ref := a.RefQualifier
+ if ref == "" {
+ ref = m.RefQualifier
+ } else if m.RefQualifier != "" {
+ if ref == "&" || m.RefQualifier == "&" {
+ ref = "&"
+ }
+ }
+ return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: ref}
+ }
+ if t, ok := a.Method.(*TypeWithQualifiers); ok {
+ return &MethodWithQualifiers{Method: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers), RefQualifier: a.RefQualifier}
+ }
+ case *TypeWithQualifiers:
+ if ft, ok := a.Base.(*FunctionType); ok {
+ return &MethodWithQualifiers{Method: ft, Qualifiers: a.Qualifiers, RefQualifier: ""}
+ }
+ if t, ok := a.Base.(*TypeWithQualifiers); ok {
+ return &TypeWithQualifiers{Base: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers)}
+ }
+ if m, ok := a.Base.(*MethodWithQualifiers); ok {
+ return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: m.RefQualifier}
+ }
+ case *ReferenceType:
+ if rt, ok := a.Base.(*ReferenceType); ok {
+ return rt
+ }
+ if rrt, ok := a.Base.(*RvalueReferenceType); ok {
+ return &ReferenceType{Base: rrt.Base}
+ }
+ case *RvalueReferenceType:
+ if rrt, ok := a.Base.(*RvalueReferenceType); ok {
+ return rrt
+ }
+ if rt, ok := a.Base.(*ReferenceType); ok {
+ return rt
+ }
+ case *ArrayType:
+ // Qualifiers on the element of an array type
+ // go on the whole array type.
+ if q, ok := a.Element.(*TypeWithQualifiers); ok {
+ return &TypeWithQualifiers{
+ Base: &ArrayType{Dimension: a.Dimension, Element: q.Base},
+ Qualifiers: q.Qualifiers,
+ }
+ }
+ case *PackExpansion:
+ // Expand the pack and replace it with a list of
+ // expressions.
+ if a.Pack != nil {
+ exprs := make([]AST, len(a.Pack.Args))
+ for i, arg := range a.Pack.Args {
+ copy := func(sub AST) AST {
+ // Replace the ArgumentPack
+ // with a specific argument.
+ if sub == a.Pack {
+ return arg
+ }
+ // Copy everything else.
+ return nil
+ }
+
+ var seen []AST
+ skip := func(sub AST) bool {
+ // Don't traverse into another
+ // pack expansion.
+ if _, ok := sub.(*PackExpansion); ok {
+ return true
+ }
+ for _, v := range seen {
+ if v == sub {
+ return true
+ }
+ }
+ seen = append(seen, sub)
+ return false
+ }
+
+ b := a.Base.Copy(copy, skip)
+ if b == nil {
+ b = a.Base
+ }
+ exprs[i] = simplify(b)
+ }
+ return &ExprList{Exprs: exprs}
+ }
+ }
+ return nil
+}
+
+// findArgumentPack walks the AST looking for the argument pack for a
+// pack expansion. We find it via a template parameter.
+func (st *state) findArgumentPack(a AST) *ArgumentPack {
+ var seen []AST
+ var ret *ArgumentPack
+ a.Traverse(func(a AST) bool {
+ if ret != nil {
+ return false
+ }
+ switch a := a.(type) {
+ case *TemplateParam:
+ if a.Template == nil || a.Index >= len(a.Template.Args) {
+ return true
+ }
+ if pack, ok := a.Template.Args[a.Index].(*ArgumentPack); ok {
+ ret = pack
+ return false
+ }
+ case *PackExpansion, *Closure, *Name:
+ return false
+ case *TaggedName, *Operator, *BuiltinType, *FunctionParam:
+ return false
+ case *UnnamedType, *FixedType, *DefaultArg:
+ return false
+ }
+ for _, v := range seen {
+ if v == a {
+ return false
+ }
+ }
+ seen = append(seen, a)
+ return true
+ })
+ return ret
+}