Full Code of ianlancetaylor/demangle for AI

master 1ff4bf46051f cached
19 files
5.4 MB
1.4M tokens
685 symbols
1 requests
Download .txt
Showing preview only (5,660K chars total). Download the full file or copy to clipboard to get everything.
Repository: ianlancetaylor/demangle
Branch: master
Commit: 1ff4bf46051f
Files: 19
Total size: 5.4 MB

Directory structure:
gitextract_d03jdduc/

├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── ast.go
├── ast_test.go
├── c++filt.go
├── cases_test.go
├── demangle.go
├── demangle_test.go
├── expected_test.go
├── fuzz_test.go
├── go.mod
├── rust.go
├── rust_expected_test.go
└── testdata/
    ├── DemangleTestCases.inc
    ├── demangle-expected
    ├── rust-demangle-expected
    └── rust.test

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.o
*.a
*.so
._*
.nfs.*
a.out
*~
*.orig
*.rej
*.exe
.*.swp
core
demangle.test


================================================
FILE: LICENSE
================================================
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.


================================================
FILE: README.md
================================================
# github.com/ianlancetaylor/demangle

A Go package that can be used to demangle C++ and Rust symbol names.


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Supported Versions

Security updates are applied only to the latest release.

## Reporting a Vulnerability

If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.

Please disclose it at [security advisory](https://github.com/ianlancetaylor/demangle/security/advisories/new).

This project is maintained by volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.


================================================
FILE: ast.go
================================================
// 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 (
	"fmt"
	"strconv"
	"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.
// This abstract syntax tree is only used for C++ symbols, not Rust symbols.
type AST interface {
	// Internal method to convert to demangled string.
	print(*printState)

	// 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.
	// The Copy method will do the right thing if copy returns nil
	// for some components of an AST but not others, so a good
	// copy function will only return non-nil for AST values that
	// need to change.
	// 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
	enclosingParams := true
	llvmStyle := false
	max := 0
	for _, o := range options {
		switch {
		case o == NoTemplateParams:
			tparams = false
		case o == NoEnclosingParams:
			enclosingParams = false
		case o == LLVMStyle:
			llvmStyle = true
		case isMaxLength(o):
			max = maxLength(o)
		}
	}

	ps := printState{
		tparams:         tparams,
		enclosingParams: enclosingParams,
		llvmStyle:       llvmStyle,
		max:             max,
		scopes:          1,
	}
	a.print(&ps)
	s := ps.buf.String()
	if max > 0 && len(s) > max {
		s = s[:max]
	}
	return s
}

// The printState type holds information needed to print an AST.
type printState struct {
	tparams         bool // whether to print template parameters
	enclosingParams bool // whether to print enclosing parameters
	llvmStyle       bool
	max             int // maximum output length

	// The scopes field is used to avoid unnecessary parentheses
	// around expressions that use > (or >>). It is incremented if
	// we output a parenthesis or something else that means that >
	// or >> won't be treated as ending a template. It starts out
	// as 1, and is set to 0 when we start writing template
	// arguments. We add parentheses around expressions using > if
	// scopes is 0. The effect is that an expression with > gets
	// parentheses if used as a template argument that is not
	// inside some other set of parentheses.
	scopes int

	// lambdaTemplateArgs is true if we are printing the template
	// arguments to a lambda with explicit template parameters.
	// In that case template parameters are printed without names.
	lambdaTemplateArgs bool

	buf  strings.Builder
	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) {
	if ps.max > 0 && ps.buf.Len() > ps.max {
		return
	}

	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]
}

// printList prints a list of AST values separated by commas,
// optionally skipping some.
func (ps *printState) printList(args []AST, skip func(AST) bool) {
	first := true
	for _, a := range args {
		if skip != nil && skip(a) {
			continue
		}
		if !first {
			ps.writeString(", ")
		}

		needsParen := false
		if ps.llvmStyle {
			if p, ok := a.(hasPrec); ok {
				if p.prec() >= precComma {
					needsParen = true
				}
			}
		}
		if needsParen {
			ps.startScope('(')
		}

		ps.print(a)

		if needsParen {
			ps.endScope(')')
		}

		first = false
	}
}

// startScope starts a scope. This is used to decide whether we need
// to parenthesize an expression using > or >>.
func (ps *printState) startScope(b byte) {
	ps.scopes++
	ps.writeByte(b)
}

// endScope closes a scope.
func (ps *printState) endScope(b byte) {
	ps.scopes--
	ps.writeByte(b)
}

// precedence is used for operator precedence. This is used to avoid
// unnecessary parentheses when printing expressions in the LLVM style.
type precedence int

// The precedence values, in order from high to low.
const (
	precPrimary precedence = iota
	precPostfix
	precUnary
	precCast
	precPtrMem
	precMul
	precAdd
	precShift
	precSpaceship
	precRel
	precEqual
	precAnd
	precXor
	precOr
	precLogicalAnd
	precLogicalOr
	precCond
	precAssign
	precComma
	precDefault
)

// hasPrec matches the AST nodes that have a prec method that returns
// the node's precedence.
type hasPrec interface {
	prec() precedence
}

// 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)
}

func (n *Name) prec() precedence {
	return precPrimary
}

// 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: "))
}

func (q *Qualified) prec() precedence {
	return precPrimary
}

// 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(' ')
	}

	scopes := ps.scopes
	ps.scopes = 0

	ps.writeByte('<')
	ps.printList(t.Args, ps.isEmpty)
	if ps.last == '>' && !ps.llvmStyle {
		// Avoid syntactic ambiguity in old versions of C++.
		ps.writeByte(' ')
	}
	ps.writeByte('>')

	ps.scopes = scopes
}

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)
}

// LambdaAuto is a lambda auto parameter.
type LambdaAuto struct {
	Index int
}

func (la *LambdaAuto) print(ps *printState) {
	// We print the index plus 1 because that is what the standard
	// demangler does.
	if ps.llvmStyle {
		ps.writeString("auto")
	} else {
		fmt.Fprintf(&ps.buf, "auto:%d", la.Index+1)
	}
}

func (la *LambdaAuto) Traverse(fn func(AST) bool) {
	fn(la)
}

func (la *LambdaAuto) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(la) {
		return nil
	}
	return fn(la)
}

func (la *LambdaAuto) GoString() string {
	return la.goString(0, "")
}

func (la *LambdaAuto) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sLambdaAuto: Index %d", indent, "", field, la.Index)
}

// TemplateParamQualifiedArg is used when the mangled name includes
// both the template parameter declaration and the template argument.
// See https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
type TemplateParamQualifiedArg struct {
	Param AST
	Arg   AST
}

func (tpqa *TemplateParamQualifiedArg) print(ps *printState) {
	// We only demangle the actual template argument.
	// That is what the LLVM demangler does.
	// The parameter disambiguates the argument,
	// but is hopefully not required by a human reader.
	ps.print(tpqa.Arg)
}

func (tpqa *TemplateParamQualifiedArg) Traverse(fn func(AST) bool) {
	if fn(tpqa) {
		tpqa.Param.Traverse(fn)
		tpqa.Arg.Traverse(fn)
	}
}

func (tpqa *TemplateParamQualifiedArg) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(tpqa) {
		return nil
	}
	param := tpqa.Param.Copy(fn, skip)
	arg := tpqa.Arg.Copy(fn, skip)
	if param == nil && arg == nil {
		return fn(tpqa)
	}
	if param == nil {
		param = tpqa.Param
	}
	if arg == nil {
		arg = tpqa.Arg
	}
	tpqa = &TemplateParamQualifiedArg{Param: param, Arg: arg}
	if r := fn(tpqa); r != nil {
		return r
	}
	return tpqa
}

func (tpqa *TemplateParamQualifiedArg) GoString() string {
	return tpqa.goString(0, "")
}

func (tpqa *TemplateParamQualifiedArg) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sTemplateParamQualifiedArg:\n%s\n%s", indent, "", field,
		tpqa.Param.goString(indent+2, "Param: "),
		tpqa.Arg.goString(indent+2, "Arg: "))
}

// Qualifiers is an ordered list of type qualifiers.
type Qualifiers struct {
	Qualifiers []AST
}

func (qs *Qualifiers) print(ps *printState) {
	first := true
	for _, q := range qs.Qualifiers {
		if !first {
			ps.writeByte(' ')
		}
		q.print(ps)
		first = false
	}
}

func (qs *Qualifiers) Traverse(fn func(AST) bool) {
	if fn(qs) {
		for _, q := range qs.Qualifiers {
			q.Traverse(fn)
		}
	}
}

func (qs *Qualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(qs) {
		return nil
	}
	changed := false
	qualifiers := make([]AST, len(qs.Qualifiers))
	for i, q := range qs.Qualifiers {
		qc := q.Copy(fn, skip)
		if qc == nil {
			qualifiers[i] = q
		} else {
			qualifiers[i] = qc
			changed = true
		}
	}
	if !changed {
		return fn(qs)
	}
	qs = &Qualifiers{Qualifiers: qualifiers}
	if r := fn(qs); r != nil {
		return r
	}
	return qs
}

func (qs *Qualifiers) GoString() string {
	return qs.goString(0, "")
}

func (qs *Qualifiers) goString(indent int, field string) string {
	quals := fmt.Sprintf("%*s%s", indent, "", field)
	for _, q := range qs.Qualifiers {
		quals += "\n"
		quals += q.goString(indent+2, "")
	}
	return quals
}

// Qualifier is a single type qualifier.
type Qualifier struct {
	Name  string // qualifier name: const, volatile, etc.
	Exprs []AST  // can be non-nil for noexcept and throw
}

func (q *Qualifier) print(ps *printState) {
	ps.writeString(q.Name)
	if len(q.Exprs) > 0 {
		ps.startScope('(')
		first := true
		for _, e := range q.Exprs {
			if el, ok := e.(*ExprList); ok && len(el.Exprs) == 0 {
				continue
			}
			if !first {
				ps.writeString(", ")
			}
			ps.print(e)
			first = false
		}
		ps.endScope(')')
	}
}

func (q *Qualifier) Traverse(fn func(AST) bool) {
	if fn(q) {
		for _, e := range q.Exprs {
			e.Traverse(fn)
		}
	}
}

func (q *Qualifier) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(q) {
		return nil
	}
	exprs := make([]AST, len(q.Exprs))
	changed := false
	for i, e := range q.Exprs {
		ec := e.Copy(fn, skip)
		if ec == nil {
			exprs[i] = e
		} else {
			exprs[i] = ec
			changed = true
		}
	}
	if !changed {
		return fn(q)
	}
	q = &Qualifier{Name: q.Name, Exprs: exprs}
	if r := fn(q); r != nil {
		return r
	}
	return q
}

func (q *Qualifier) GoString() string {
	return q.goString(0, "Qualifier: ")
}

func (q *Qualifier) goString(indent int, field string) string {
	qs := fmt.Sprintf("%*s%s%s", indent, "", field, q.Name)
	if len(q.Exprs) > 0 {
		for i, e := range q.Exprs {
			qs += "\n"
			qs += e.goString(indent+2, fmt.Sprintf("%d: ", i))
		}
	}
	return qs
}

// TypeWithQualifiers is a type with standard qualifiers.
type TypeWithQualifiers struct {
	Base       AST
	Qualifiers AST
}

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.print(twq.Qualifiers)
		// In implausible situations like a throw qualified by a throw,
		// we may have printed the qualifier already,
		// so check the length of ps.inner again.
		if len(ps.inner) > 0 {
			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.print(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)
	quals := twq.Qualifiers.Copy(fn, skip)
	if base == nil && quals == nil {
		return fn(twq)
	}
	if base == nil {
		base = twq.Base
	}
	if quals == nil {
		quals = twq.Qualifiers
	}
	twq = &TypeWithQualifiers{Base: base, Qualifiers: quals}
	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:\n%s\n%s", indent, "", field,
		twq.Qualifiers.goString(indent+2, "Qualifiers: "),
		twq.Base.goString(indent+2, "Base: "))
}

// MethodWithQualifiers is a method with qualifiers.
type MethodWithQualifiers struct {
	Method       AST
	Qualifiers   AST
	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 mwq.Qualifiers != nil {
			ps.writeByte(' ')
			ps.print(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 mwq.Qualifiers != nil {
		ps.writeByte(' ')
		ps.print(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)
	var quals AST
	if mwq.Qualifiers != nil {
		quals = mwq.Qualifiers.Copy(fn, skip)
	}
	if method == nil && quals == nil {
		return fn(mwq)
	}
	if method == nil {
		method = mwq.Method
	}
	if quals == nil {
		quals = mwq.Qualifiers
	}
	mwq = &MethodWithQualifiers{Method: method, Qualifiers: quals, 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 mwq.Qualifiers != nil {
		q += "\n" + mwq.Qualifiers.goString(indent+2, "Qualifiers: ")
	}
	if mwq.RefQualifier != "" {
		if q != "" {
			q += "\n"
		}
		q += fmt.Sprintf("%*s%s%s", indent+2, "", "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) {
	name := bt.Name
	if ps.llvmStyle && name == "decltype(nullptr)" {
		name = "std::nullptr_t"
	}
	ps.writeString(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)
}

func (bt *BuiltinType) prec() precedence {
	return precPrimary
}

// 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, ""))
}

// SuffixType is an type with an arbitrary suffix.
type SuffixType struct {
	Base   AST
	Suffix string
}

func (st *SuffixType) print(ps *printState) {
	printBase(ps, st, st.Base)
}

func (st *SuffixType) printInner(ps *printState) {
	ps.writeByte(' ')
	ps.writeString(st.Suffix)
}

func (st *SuffixType) Traverse(fn func(AST) bool) {
	if fn(st) {
		st.Base.Traverse(fn)
	}
}

func (st *SuffixType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(st) {
		return nil
	}
	base := st.Base.Copy(fn, skip)
	if base == nil {
		return fn(st)
	}
	st = &SuffixType{Base: base, Suffix: st.Suffix}
	if r := fn(st); r != nil {
		return r
	}
	return st
}

func (st *SuffixType) GoString() string {
	return st.goString(0, "")
}

func (st *SuffixType) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sSuffixType: %s\n%s", indent, "", field,
		st.Suffix, st.Base.goString(indent+2, "Base: "))
}

// TransformedType is a builtin type with a template argument.
type TransformedType struct {
	Name string
	Base AST
}

func (tt *TransformedType) print(ps *printState) {
	ps.writeString(tt.Name)
	ps.startScope('(')
	ps.print(tt.Base)
	ps.endScope(')')
}

func (tt *TransformedType) Traverse(fn func(AST) bool) {
	if fn(tt) {
		tt.Base.Traverse(fn)
	}
}

func (tt *TransformedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(tt) {
		return nil
	}
	base := tt.Base.Copy(fn, skip)
	if base == nil {
		return fn(tt)
	}
	tt = &TransformedType{Name: tt.Name, Base: base}
	if r := fn(tt); r != nil {
		return r
	}
	return tt
}

func (tt *TransformedType) GoString() string {
	return tt.goString(0, "")
}

func (tt *TransformedType) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sTransformedType: %s\n%s", indent, "", field,
		tt.Name, tt.Base.goString(indent+2, "Base: "))
}

// VendorQualifier is a type qualified by a vendor-specific qualifier.
type VendorQualifier struct {
	Qualifier AST
	Type      AST
}

func (vq *VendorQualifier) print(ps *printState) {
	if ps.llvmStyle {
		ps.print(vq.Type)
		vq.printInner(ps)
	} else {
		ps.inner = append(ps.inner, vq)
		ps.print(vq.Type)
		if len(ps.inner) > 0 {
			ps.printOneInner(nil)
		}
	}
}

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.writeByte(' ')
			ps.startScope('(')
			ps.printInner(false)
			ps.endScope(')')
		}
	}
	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.
type FunctionType struct {
	Return AST
	Args   []AST

	// The forLocalName field reports whether this FunctionType
	// was created for a local name. With the default GNU demangling
	// output we don't print the return type in that case.
	ForLocalName bool
}

func (ft *FunctionType) print(ps *printState) {
	retType := ft.Return
	if ft.ForLocalName && (!ps.enclosingParams || !ps.llvmStyle) {
		retType = nil
	}
	if retType != nil {
		// Pass the return type as an inner type in order to
		// print the arguments in the right location.
		ps.inner = append(ps.inner, ft)
		ps.print(retType)
		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.startScope('(')
	}

	save := ps.printInner(true)

	if paren {
		ps.endScope(')')
	}

	ps.startScope('(')
	if !ft.ForLocalName || ps.enclosingParams {
		first := true
		for _, a := range ft.Args {
			if ps.isEmpty(a) {
				continue
			}
			if !first {
				ps.writeString(", ")
			}
			ps.print(a)
			first = false
		}
	}
	ps.endScope(')')

	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,
		ForLocalName: ft.ForLocalName,
	}
	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 forLocalName string
	if ft.ForLocalName {
		forLocalName = " ForLocalName: true"
	}
	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:%s\n%s\n%s", indent, "", field,
		forLocalName, 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 if ps.llvmStyle {
		if fp.Index == 1 {
			ps.writeString("fp")
		} else {
			fmt.Fprintf(&ps.buf, "fp%d", fp.Index-2)
		}
	} else {
		fmt.Fprintf(&ps.buf, "{parm#%d}", fp.Index)
	}
}

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)
}

func (fp *FunctionParam) prec() precedence {
	return precPrimary
}

// 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: "))
}

// BinaryFP is a binary floating-point type.
type BinaryFP struct {
	Bits   int
	Suffix string
}

func (bfp *BinaryFP) print(ps *printState) {
	fmt.Fprintf(&ps.buf, "_Float%d%s", bfp.Bits, bfp.Suffix)
}

func (bfp *BinaryFP) Traverse(fn func(AST) bool) {
	fn(bfp)
}

func (bfp *BinaryFP) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(bfp) {
		return nil
	}
	return fn(bfp)
}

func (bfp *BinaryFP) GoString() string {
	return bfp.goString(0, "")
}

func (bfp *BinaryFP) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sBinaryFP: Bits: %d Suffix: %s", indent, "", field, bfp.Bits, bfp.Suffix)
}

// BitIntType is the C++23 _BitInt(N) type.
type BitIntType struct {
	Size   AST
	Signed bool
}

func (bt *BitIntType) print(ps *printState) {
	if !bt.Signed {
		ps.writeString("unsigned ")
	}
	ps.writeString("_BitInt")
	ps.startScope('(')
	ps.print(bt.Size)
	ps.endScope(')')
}

func (bt *BitIntType) Traverse(fn func(AST) bool) {
	if fn(bt) {
		bt.Size.Traverse(fn)
	}
}

func (bt *BitIntType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(bt) {
		return nil
	}
	size := bt.Size.Copy(fn, skip)
	if size == nil {
		return fn(bt)
	}
	bt = &BitIntType{Size: size, Signed: bt.Signed}
	if r := fn(bt); r != nil {
		return r
	}
	return bt
}

func (bt *BitIntType) GoString() string {
	return bt.goString(0, "")
}

func (bt *BitIntType) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sBitIntType: Signed: %t\n%s", indent, "", field,
		bt.Signed,
		bt.Size.goString(indent+2, "Size: "))
}

// 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) {
	end := byte(')')
	if ps.llvmStyle {
		ps.writeString(" vector[")
		end = ']'
	} else {
		ps.writeString(" __vector(")
	}
	ps.print(vt.Dimension)
	ps.writeByte(end)
}

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: "))
}

// ElaboratedType is an elaborated struct/union/enum type.
type ElaboratedType struct {
	Kind string
	Type AST
}

func (et *ElaboratedType) print(ps *printState) {
	ps.writeString(et.Kind)
	ps.writeString(" ")
	et.Type.print(ps)
}

func (et *ElaboratedType) Traverse(fn func(AST) bool) {
	if fn(et) {
		et.Type.Traverse(fn)
	}
}

func (et *ElaboratedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(et) {
		return nil
	}
	typ := et.Type.Copy(fn, skip)
	if typ == nil {
		return fn(et)
	}
	et = &ElaboratedType{Kind: et.Kind, Type: typ}
	if r := fn(et); r != nil {
		return r
	}
	return et
}

func (et *ElaboratedType) GoString() string {
	return et.goString(0, "")
}

func (et *ElaboratedType) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sElaboratedtype: Kind: %s\n%s", indent, "", field,
		et.Kind, et.Type.goString(indent+2, "Expr: "))
}

// Decltype is the decltype operator.
type Decltype struct {
	Expr AST
}

func (dt *Decltype) print(ps *printState) {
	ps.writeString("decltype")
	if !ps.llvmStyle {
		ps.writeString(" ")
	}
	ps.startScope('(')
	ps.print(dt.Expr)
	ps.endScope(')')
}

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
	precedence precedence
}

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)
}

func (op *Operator) prec() precedence {
	return op.precedence
}

// Constructor is a constructor.
type Constructor struct {
	Name AST
	Base AST // base class of inheriting constructor
}

func (c *Constructor) print(ps *printState) {
	ps.print(c.Name)
	// We don't include the base class in the demangled string.
}

func (c *Constructor) Traverse(fn func(AST) bool) {
	if fn(c) {
		c.Name.Traverse(fn)
		if c.Base != nil {
			c.Base.Traverse(fn)
		}
	}
}

func (c *Constructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(c) {
		return nil
	}
	name := c.Name.Copy(fn, skip)
	var base AST
	if c.Base != nil {
		base = c.Base.Copy(fn, skip)
	}
	if name == nil && base == nil {
		return fn(c)
	}
	if name == nil {
		name = c.Name
	}
	if base == nil {
		base = c.Base
	}
	c = &Constructor{Name: name, Base: base}
	if r := fn(c); r != nil {
		return r
	}
	return c
}

func (c *Constructor) GoString() string {
	return c.goString(0, "")
}

func (c *Constructor) goString(indent int, field string) string {
	var sb strings.Builder
	fmt.Fprintf(&sb, "%*s%sConstructor:\n", indent, "", field)
	if c.Base != nil {
		fmt.Fprintf(&sb, "%s\n", c.Base.goString(indent+2, "Base: "))
	}
	fmt.Fprintf(&sb, "%s", c.Name.goString(indent+2, "Name: "))
	return sb.String()
}

// Destructor is a destructor.
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 {
		if ps.llvmStyle {
			ps.print(pe.Base)
		} else {
			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) {
	if ps.llvmStyle {
		ps.writeString("sizeof...")
		ps.startScope('(')
		ps.print(sp.Pack)
		ps.endScope(')')
	} else {
		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)
}

// TemplateParamName is the name of a template parameter that the
// demangler introduced for a lambda that has explicit template
// parameters.  This is a prefix with an index.
type TemplateParamName struct {
	Prefix string
	Index  int
}

func (tpn *TemplateParamName) print(ps *printState) {
	ps.writeString(tpn.Prefix)
	if ps.llvmStyle {
		if tpn.Index > 0 {
			ps.writeString(fmt.Sprintf("%d", tpn.Index-1))
		}
	} else {
		ps.writeString(fmt.Sprintf("%d", tpn.Index))
	}
}

func (tpn *TemplateParamName) Traverse(fn func(AST) bool) {
	fn(tpn)
}

func (tpn *TemplateParamName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(tpn) {
		return nil
	}
	return fn(tpn)
}

func (tpn *TemplateParamName) GoString() string {
	return tpn.goString(0, "")
}

func (tpn *TemplateParamName) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sTemplateParamName: %s%d", indent, "", field, tpn.Prefix, tpn.Index)
}

// TypeTemplateParam is a type template parameter that appears in a
// lambda with explicit template parameters.
type TypeTemplateParam struct {
	Name AST
}

func (ttp *TypeTemplateParam) print(ps *printState) {
	ps.writeString("typename")
	if ps.llvmStyle {
		ps.writeByte(' ')
	}
	ps.printInner(false)
	if ps.llvmStyle || !ps.lambdaTemplateArgs {
		if !ps.llvmStyle {
			ps.writeByte(' ')
		}
		ps.print(ttp.Name)
	}
}

func (ttp *TypeTemplateParam) Traverse(fn func(AST) bool) {
	if fn(ttp) {
		ttp.Name.Traverse(fn)
	}
}

func (ttp *TypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(ttp) {
		return nil
	}
	name := ttp.Name.Copy(fn, skip)
	if name == nil {
		return fn(ttp)
	}
	ttp = &TypeTemplateParam{Name: name}
	if r := fn(ttp); r != nil {
		return r
	}
	return ttp
}

func (ttp *TypeTemplateParam) GoString() string {
	return ttp.goString(0, "")
}

func (ttp *TypeTemplateParam) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sTypeTemplateParam:\n%s", indent, "", field,
		ttp.Name.goString(indent+2, "Name"))
}

// NonTypeTemplateParam is a non-type template parameter that appears
// in a lambda with explicit template parameters.
type NonTypeTemplateParam struct {
	Name AST
	Type AST
}

func (nttp *NonTypeTemplateParam) print(ps *printState) {
	ps.inner = append(ps.inner, nttp)
	ps.print(nttp.Type)
	if len(ps.inner) > 0 {
		if ps.llvmStyle || !ps.lambdaTemplateArgs {
			ps.writeByte(' ')
			ps.print(nttp.Name)
		}
		ps.inner = ps.inner[:len(ps.inner)-1]
	}
}

func (nttp *NonTypeTemplateParam) printInner(ps *printState) {
	ps.print(nttp.Name)
}

func (nttp *NonTypeTemplateParam) Traverse(fn func(AST) bool) {
	if fn(nttp) {
		nttp.Name.Traverse(fn)
		nttp.Type.Traverse(fn)
	}
}

func (nttp *NonTypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(nttp) {
		return nil
	}
	name := nttp.Name.Copy(fn, skip)
	typ := nttp.Type.Copy(fn, skip)
	if name == nil && typ == nil {
		return fn(nttp)
	}
	if name == nil {
		name = nttp.Name
	}
	if typ == nil {
		typ = nttp.Type
	}
	nttp = &NonTypeTemplateParam{Name: name, Type: typ}
	if r := fn(nttp); r != nil {
		return r
	}
	return nttp
}

func (nttp *NonTypeTemplateParam) GoString() string {
	return nttp.goString(0, "")
}

func (nttp *NonTypeTemplateParam) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sNonTypeTemplateParam:\n%s\n%s", indent, "", field,
		nttp.Name.goString(indent+2, "Name: "),
		nttp.Type.goString(indent+2, "Type: "))
}

// TemplateTemplateParam is a template template parameter that appears
// in a lambda with explicit template parameters.
type TemplateTemplateParam struct {
	Name       AST
	Params     []AST
	Constraint AST
}

func (ttp *TemplateTemplateParam) print(ps *printState) {
	scopes := ps.scopes
	ps.scopes = 0
	lambdaTemplateArgs := ps.lambdaTemplateArgs
	ps.lambdaTemplateArgs = true
	inner := ps.inner
	ps.inner = nil

	ps.writeString("template<")
	ps.printList(ttp.Params, nil)
	ps.writeString("> ")
	if ps.llvmStyle {
		ps.writeString("typename")
	} else {
		ps.writeString("class")
	}

	ps.scopes = scopes
	ps.lambdaTemplateArgs = lambdaTemplateArgs
	ps.inner = inner

	ps.printInner(false)

	if ps.llvmStyle || !ps.lambdaTemplateArgs {
		ps.writeByte(' ')
		ps.print(ttp.Name)
	}

	if ttp.Constraint != nil {
		ps.writeString(" requires ")
		ps.print(ttp.Constraint)
	}
}

func (ttp *TemplateTemplateParam) Traverse(fn func(AST) bool) {
	if fn(ttp) {
		ttp.Name.Traverse(fn)
		for _, param := range ttp.Params {
			param.Traverse(fn)
		}
		if ttp.Constraint != nil {
			ttp.Constraint.Traverse(fn)
		}
	}
}

func (ttp *TemplateTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(ttp) {
		return nil
	}

	changed := false

	name := ttp.Name.Copy(fn, skip)
	if name == nil {
		name = ttp.Name
	} else {
		changed = true
	}

	params := make([]AST, len(ttp.Params))
	for i, p := range ttp.Params {
		pc := p.Copy(fn, skip)
		if pc == nil {
			params[i] = p
		} else {
			params[i] = pc
			changed = true
		}
	}

	var constraint AST
	if ttp.Constraint != nil {
		constraint = ttp.Constraint.Copy(fn, skip)
		if constraint == nil {
			constraint = ttp.Constraint
		} else {
			changed = true
		}
	}

	if !changed {
		return fn(ttp)
	}

	ttp = &TemplateTemplateParam{
		Name:       name,
		Params:     params,
		Constraint: constraint,
	}
	if r := fn(ttp); r != nil {
		return r
	}
	return ttp
}

func (ttp *TemplateTemplateParam) GoString() string {
	return ttp.goString(0, "")
}

func (ttp *TemplateTemplateParam) goString(indent int, field string) string {
	var params strings.Builder
	fmt.Fprintf(&params, "%*sParams:", indent+2, "")
	for i, p := range ttp.Params {
		params.WriteByte('\n')
		params.WriteString(p.goString(indent+4, fmt.Sprintf("%d: ", i)))
	}
	var constraint string
	if ttp.Constraint == nil {
		constraint = fmt.Sprintf("%*sConstraint: nil", indent+2, "")
	} else {
		constraint = ttp.Constraint.goString(indent+2, "Constraint: ")
	}
	return fmt.Sprintf("%*s%sTemplateTemplateParam:\n%s\n%s\n%s", indent, "", field,
		ttp.Name.goString(indent+2, "Name: "),
		params.String(),
		constraint)
}

// ConstrainedTypeTemplateParam is a constrained template type
// parameter declaration.
type ConstrainedTypeTemplateParam struct {
	Name       AST
	Constraint AST
}

func (cttp *ConstrainedTypeTemplateParam) print(ps *printState) {
	ps.inner = append(ps.inner, cttp)
	ps.print(cttp.Constraint)
	if len(ps.inner) > 0 {
		ps.writeByte(' ')
		ps.print(cttp.Name)
		ps.inner = ps.inner[:len(ps.inner)-1]
	}
}

func (cttp *ConstrainedTypeTemplateParam) printInner(ps *printState) {
	ps.print(cttp.Name)
}

func (cttp *ConstrainedTypeTemplateParam) Traverse(fn func(AST) bool) {
	if fn(cttp) {
		cttp.Name.Traverse(fn)
		cttp.Constraint.Traverse(fn)
	}
}

func (cttp *ConstrainedTypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(cttp) {
		return nil
	}
	name := cttp.Name.Copy(fn, skip)
	constraint := cttp.Constraint.Copy(fn, skip)
	if name == nil && constraint == nil {
		return fn(cttp)
	}
	if name == nil {
		name = cttp.Name
	}
	if constraint == nil {
		constraint = cttp.Constraint
	}
	cttp = &ConstrainedTypeTemplateParam{Name: name, Constraint: constraint}
	if r := fn(cttp); r != nil {
		return r
	}
	return cttp
}

func (cttp *ConstrainedTypeTemplateParam) GoString() string {
	return cttp.goString(0, "")
}

func (cttp *ConstrainedTypeTemplateParam) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sConstrainedTypeTemplateParam\n%s\n%s", indent, "", field,
		cttp.Name.goString(indent+2, "Name: "),
		cttp.Constraint.goString(indent+2, "Constraint: "))
}

// TemplateParamPack is a template parameter pack that appears in a
// lambda with explicit template parameters.
type TemplateParamPack struct {
	Param AST
}

func (tpp *TemplateParamPack) print(ps *printState) {
	holdInner := ps.inner
	defer func() { ps.inner = holdInner }()

	ps.inner = []AST{tpp}
	nttp, isNTTP := tpp.Param.(*NonTypeTemplateParam)
	if isNTTP {
		ps.print(nttp.Type)
	} else {
		ps.print(tpp.Param)
	}
	if len(ps.inner) > 0 {
		ps.writeString("...")
		if isNTTP && (ps.llvmStyle || !ps.lambdaTemplateArgs) {
			ps.writeByte(' ')
			ps.print(nttp.Name)
		}
	}
}

func (tpp *TemplateParamPack) printInner(ps *printState) {
	ps.writeString("...")
	if nttp, ok := tpp.Param.(*NonTypeTemplateParam); ok {
		ps.print(nttp.Name)
	}
}

func (tpp *TemplateParamPack) Traverse(fn func(AST) bool) {
	if fn(tpp) {
		tpp.Param.Traverse(fn)
	}
}

func (tpp *TemplateParamPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(tpp) {
		return nil
	}
	param := tpp.Param.Copy(fn, skip)
	if param == nil {
		return fn(tpp)
	}
	tpp = &TemplateParamPack{Param: param}
	if r := fn(tpp); r != nil {
		return r
	}
	return tpp
}

func (tpp *TemplateParamPack) GoString() string {
	return tpp.goString(0, "")
}

func (tpp *TemplateParamPack) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sTemplateParamPack:\n%s", indent, "", field,
		tpp.Param.goString(indent+2, "Param: "))
}

// Cast is a type cast.
type Cast struct {
	To AST
}

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: "))
}

func (c *Cast) prec() precedence {
	return precCast
}

// 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:
	case *FunctionParam:
		if ps.llvmStyle {
			paren = true
		}
	case *Qualified:
		if v.LocalName {
			paren = true
		}
	default:
		paren = true
	}
	if paren {
		ps.startScope('(')
	}
	ps.print(val)
	if paren {
		ps.endScope(')')
	}
}

// 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) {
	op, _ := u.Op.(*Operator)
	expr := u.Expr

	// Don't print the argument list when taking the address of a
	// function.
	if !ps.llvmStyle {
		if op != nil && op.Name == "&" {
			if t, ok := expr.(*Typed); ok {
				if _, ok := t.Type.(*FunctionType); ok {
					expr = t.Name
				}
			}
		}
	}

	if u.Suffix {
		if ps.llvmStyle {
			wantParens := true
			opPrec := precUnary
			if op != nil {
				opPrec = op.precedence
			}
			if p, ok := expr.(hasPrec); ok {
				if p.prec() < opPrec {
					wantParens = false
				}
			}
			if wantParens {
				ps.startScope('(')
			}
			ps.print(expr)
			if wantParens {
				ps.endScope(')')
			}
		} else {
			parenthesize(ps, expr)
		}
	}

	if op != nil {
		ps.writeString(op.Name)
		if ps.llvmStyle && op.Name == "noexcept" {
			ps.writeByte(' ')
		}
	} else if c, ok := u.Op.(*Cast); ok {
		ps.startScope('(')
		ps.print(c.To)
		ps.endScope(')')
	} else {
		ps.print(u.Op)
	}

	if !u.Suffix {
		alwaysParens := u.SizeofType || (op != nil && (op.Name == "__alignof__" || op.Name == "noexcept"))
		if op != nil && op.Name == "::" {
			// Don't use parentheses after ::.
			ps.print(expr)
		} else if alwaysParens {
			ps.startScope('(')
			ps.print(expr)
			ps.endScope(')')
		} else if ps.llvmStyle {
			var wantParens bool
			switch {
			case op == nil:
				wantParens = true
			case op.Name == `operator"" `:
				wantParens = false
			case op.Name == "&":
				wantParens = false
			case op.Name == "delete" || op.Name == "delete[]":
				wantParens = false
			case op.Name == "alignof ":
				wantParens = true
			case op.Name == "sizeof ":
				wantParens = true
			case op.Name == "typeid ":
				wantParens = true
			default:
				wantParens = true
				if p, ok := expr.(hasPrec); ok {
					if p.prec() < op.precedence {
						wantParens = false
					}
				}
			}
			if wantParens {
				ps.startScope('(')
			}
			ps.print(expr)
			if wantParens {
				ps.endScope(')')
			}
		} 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: "))
}

func (u *Unary) prec() precedence {
	if p, ok := u.Op.(hasPrec); ok {
		return p.prec()
	}
	return precDefault
}

// isDesignatedInitializer reports whether x is a designated
// initializer.
func isDesignatedInitializer(x AST) bool {
	switch x := x.(type) {
	case *Binary:
		if op, ok := x.Op.(*Operator); ok {
			if op.Name == "]=" {
				return true
			}
			if op.Name != "=" {
				return false
			}
			if _, ok := x.Left.(*Literal); ok {
				return false
			}
			return true
		}
	case *Trinary:
		if op, ok := x.Op.(*Operator); ok {
			return op.Name == "[...]="
		}
	}
	return false
}

// 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)

		scopes := ps.scopes
		ps.scopes = 0

		ps.writeByte('<')
		ps.print(b.Left)
		ps.writeString(">")

		ps.scopes = scopes

		ps.startScope('(')
		ps.print(b.Right)
		ps.endScope(')')
		return
	}

	if isDesignatedInitializer(b) {
		if op.Name == "=" {
			ps.writeByte('.')
		} else {
			ps.writeByte('[')
		}
		ps.print(b.Left)
		if op.Name == "]=" {
			ps.writeByte(']')
		}
		if isDesignatedInitializer(b.Right) {
			// Don't add anything between designated
			// initializer chains.
			ps.print(b.Right)
		} else {
			if ps.llvmStyle {
				ps.writeString(" = ")
				ps.print(b.Right)
			} else {
				ps.writeByte('=')
				parenthesize(ps, b.Right)
			}
		}
		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.
	needsOuterParen := op != nil && (op.Name == ">" || op.Name == ">>")
	if ps.llvmStyle && ps.scopes > 0 {
		needsOuterParen = false
	}
	if needsOuterParen {
		ps.startScope('(')
	}

	left := b.Left

	skipParens := false
	addSpaces := ps.llvmStyle
	if ps.llvmStyle && op != nil {
		switch op.Name {
		case ".", "->", "->*":
			addSpaces = false
		}
	}

	// For a function call in an expression, don't print the types
	// of the arguments unless there is a return type.
	if op != nil && strings.HasPrefix(op.Name, "()") {
		if ty, ok := b.Left.(*Typed); ok {
			if ft, ok := ty.Type.(*FunctionType); ok {
				if ft.Return == nil {
					left = ty.Name
				} else {
					if op.Name != "() " {
						skipParens = true
					}
				}
			} else {
				left = ty.Name
			}
		}
		if ps.llvmStyle && op.Name != "() " {
			skipParens = true
		}
	}

	if skipParens {
		ps.print(left)
	} else if ps.llvmStyle {
		prec := precPrimary
		if p, ok := left.(hasPrec); ok {
			prec = p.prec()
		}
		needsParen := op.Name == "() "
		if prec > b.prec() {
			needsParen = true
		}
		if needsParen {
			ps.startScope('(')
		}

		ps.print(left)

		if needsParen {
			ps.endScope(')')
		}
	} else {
		parenthesize(ps, left)
	}

	if op != nil && op.Name == "[]" {
		ps.writeByte('[')
		ps.print(b.Right)
		ps.writeByte(']')
		return
	}

	if op != nil {
		if !strings.HasPrefix(op.Name, "()") {
			if addSpaces && op.Name != "," {
				ps.writeByte(' ')
			}
			ps.writeString(op.Name)
			if addSpaces {
				ps.writeByte(' ')
			}
		}
	} else {
		ps.print(b.Op)
	}

	if ps.llvmStyle {
		prec := precPrimary
		if p, ok := b.Right.(hasPrec); ok {
			prec = p.prec()
		}
		needsParen := false
		if prec >= b.prec() {
			needsParen = true
		}
		if needsParen {
			ps.startScope('(')
		}

		ps.print(b.Right)

		if needsParen {
			ps.endScope(')')
		}
	} else {
		parenthesize(ps, b.Right)
	}

	if needsOuterParen {
		ps.endScope(')')
	}
}

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: "))
}

func (b *Binary) prec() precedence {
	if p, ok := b.Op.(hasPrec); ok {
		return p.prec()
	}
	return precDefault
}

// 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) {
	if isDesignatedInitializer(t) {
		ps.writeByte('[')
		ps.print(t.First)
		ps.writeString(" ... ")
		ps.print(t.Second)
		ps.writeByte(']')
		if isDesignatedInitializer(t.Third) {
			// Don't add anything between designated
			// initializer chains.
			ps.print(t.Third)
		} else {
			if ps.llvmStyle {
				ps.writeString(" = ")
				ps.print(t.Third)
			} else {
				ps.writeByte('=')
				parenthesize(ps, t.Third)
			}
		}
		return
	}

	if ps.llvmStyle {
		wantParens := true
		opPrec := precPrimary
		if op, ok := t.Op.(*Operator); ok {
			opPrec = op.precedence
		}
		if p, ok := t.First.(hasPrec); ok {
			if p.prec() < opPrec {
				wantParens = false
			}
		}
		if wantParens {
			ps.startScope('(')
		}
		ps.print(t.First)
		if wantParens {
			ps.endScope(')')
		}
	} else {
		parenthesize(ps, t.First)
	}

	if ps.llvmStyle {
		ps.writeString(" ? ")
	} else {
		ps.writeByte('?')
	}

	if ps.llvmStyle {
		wantParens := true
		if p, ok := t.Second.(hasPrec); ok {
			if p.prec() < precDefault {
				wantParens = false
			}
		}
		if wantParens {
			ps.startScope('(')
		}
		ps.print(t.Second)
		if wantParens {
			ps.endScope(')')
		}
	} else {
		parenthesize(ps, t.Second)
	}

	ps.writeString(" : ")

	if ps.llvmStyle {
		wantParens := true
		if p, ok := t.Third.(hasPrec); ok {
			if p.prec() < precAssign {
				wantParens = false
			}
		}
		if wantParens {
			ps.startScope('(')
		}
		ps.print(t.Third)
		if wantParens {
			ps.endScope(')')
		}
	} else {
		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 {
			if ps.llvmStyle {
				ps.writeByte(' ')
			}
			ps.writeString(op.Name)
			if ps.llvmStyle {
				ps.writeByte(' ')
			}
		} else {
			ps.print(f.Op)
		}
	}
	foldParenthesize := func(a AST) {
		if ps.llvmStyle {
			prec := precDefault
			if p, ok := a.(hasPrec); ok {
				prec = p.prec()
			}
			needsParen := false
			if prec > precCast {
				needsParen = true
			}
			if needsParen {
				ps.startScope('(')
			}
			ps.print(a)
			if needsParen {
				ps.endScope(')')
			}
		} else {
			parenthesize(ps, a)
		}
	}

	if f.Arg2 == nil {
		if f.Left {
			ps.startScope('(')
			ps.writeString("...")
			printOp()
			foldParenthesize(f.Arg1)
			ps.endScope(')')
		} else {
			ps.startScope('(')
			foldParenthesize(f.Arg1)
			printOp()
			ps.writeString("...")
			ps.endScope(')')
		}
	} else {
		ps.startScope('(')
		foldParenthesize(f.Arg1)
		printOp()
		ps.writeString("...")
		printOp()
		foldParenthesize(f.Arg2)
		ps.endScope(')')
	}
}

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: "))
	}
}

// Subobject is a a reference to an offset in an expression.  This is
// used for C++20 manglings of class types used as the type of
// non-type template arguments.
//
// See https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
type Subobject struct {
	Type      AST
	SubExpr   AST
	Offset    int
	Selectors []int
	PastEnd   bool
}

func (so *Subobject) print(ps *printState) {
	ps.print(so.SubExpr)
	ps.writeString(".<")
	ps.print(so.Type)
	ps.writeString(fmt.Sprintf(" at offset %d>", so.Offset))
}

func (so *Subobject) Traverse(fn func(AST) bool) {
	if fn(so) {
		so.Type.Traverse(fn)
		so.SubExpr.Traverse(fn)
	}
}

func (so *Subobject) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(so) {
		return nil
	}
	typ := so.Type.Copy(fn, skip)
	subExpr := so.SubExpr.Copy(fn, skip)
	if typ == nil && subExpr == nil {
		return nil
	}
	if typ == nil {
		typ = so.Type
	}
	if subExpr == nil {
		subExpr = so.SubExpr
	}
	so = &Subobject{
		Type:      typ,
		SubExpr:   subExpr,
		Offset:    so.Offset,
		Selectors: so.Selectors,
		PastEnd:   so.PastEnd,
	}
	if r := fn(so); r != nil {
		return r
	}
	return so
}

func (so *Subobject) GoString() string {
	return so.goString(0, "")
}

func (so *Subobject) goString(indent int, field string) string {
	var selectors string
	for _, s := range so.Selectors {
		selectors += fmt.Sprintf(" %d", s)
	}
	return fmt.Sprintf("%*s%sSubobject:\n%s\n%s\n%*sOffset: %d\n%*sSelectors:%s\n%*sPastEnd: %t",
		indent, "", field,
		so.Type.goString(indent+2, "Type: "),
		so.SubExpr.goString(indent+2, "SubExpr: "),
		indent+2, "", so.Offset,
		indent+2, "", selectors,
		indent+2, "", so.PastEnd)
}

// PtrMemCast is a conversion of an expression to a pointer-to-member
// type.  This is used for C++20 manglings of class types used as the
// type of non-type template arguments.
//
// See https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
type PtrMemCast struct {
	Type   AST
	Expr   AST
	Offset int
}

func (pmc *PtrMemCast) print(ps *printState) {
	ps.startScope('(')
	ps.print(pmc.Type)
	ps.writeString(")(")
	ps.print(pmc.Expr)
	ps.endScope(')')
}

func (pmc *PtrMemCast) Traverse(fn func(AST) bool) {
	if fn(pmc) {
		pmc.Type.Traverse(fn)
		pmc.Expr.Traverse(fn)
	}
}

func (pmc *PtrMemCast) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(pmc) {
		return nil
	}
	typ := pmc.Type.Copy(fn, skip)
	expr := pmc.Expr.Copy(fn, skip)
	if typ == nil && expr == nil {
		return nil
	}
	if typ == nil {
		typ = pmc.Type
	}
	if expr == nil {
		expr = pmc.Expr
	}
	pmc = &PtrMemCast{
		Type:   typ,
		Expr:   expr,
		Offset: pmc.Offset,
	}
	if r := fn(pmc); r != nil {
		return r
	}
	return pmc
}

func (pmc *PtrMemCast) GoString() string {
	return pmc.goString(0, "")
}

func (pmc *PtrMemCast) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sPtrMemCast:\n%s\n%s\n%*sOffset: %d",
		indent, "", field,
		pmc.Type.goString(indent+2, "Type: "),
		pmc.Expr.goString(indent+2, "Expr: "),
		indent+2, "", pmc.Offset)
}

// New is a use of operator new in an expression.
type New struct {
	Op    AST
	Place AST
	Type  AST
	Init  AST
}

func (n *New) print(ps *printState) {
	if !ps.llvmStyle {
		// Op doesn't really matter for printing--we always print "new".
		ps.writeString("new ")
	} else {
		op, _ := n.Op.(*Operator)
		if op != nil {
			ps.writeString(op.Name)
			if n.Place == nil {
				ps.writeByte(' ')
			}
		} else {
			ps.print(n.Op)
		}
	}
	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 if b.Name == "decltype(nullptr)" && (l.Val == "" || l.Val == "0") {
			if ps.llvmStyle {
				ps.writeString("nullptr")
			} else {
				ps.print(l.Type)
			}
			return
		} else {
			isFloat = builtinTypeFloat[b.Name]
		}
	}

	ps.startScope('(')
	ps.print(l.Type)
	ps.endScope(')')

	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)
}

func (l *Literal) prec() precedence {
	return precPrimary
}

// StringLiteral is a string literal.
type StringLiteral struct {
	Type AST
}

func (sl *StringLiteral) print(ps *printState) {
	ps.writeString(`"<`)
	sl.Type.print(ps)
	ps.writeString(`>"`)
}

func (sl *StringLiteral) Traverse(fn func(AST) bool) {
	if fn(sl) {
		sl.Type.Traverse(fn)
	}
}

func (sl *StringLiteral) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(sl) {
		return nil
	}
	typ := sl.Type.Copy(fn, skip)
	if typ == nil {
		return fn(sl)
	}
	sl = &StringLiteral{Type: typ}
	if r := fn(sl); r != nil {
		return r
	}
	return sl
}

func (sl *StringLiteral) GoString() string {
	return sl.goString(0, "")
}

func (sl *StringLiteral) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sStringLiteral:\n%s", indent, "", field,
		sl.Type.goString(indent+2, ""))
}

// LambdaExpr is a literal that is a lambda expression.
type LambdaExpr struct {
	Type AST
}

func (le *LambdaExpr) print(ps *printState) {
	ps.writeString("[]")
	if cl, ok := le.Type.(*Closure); ok {
		cl.printTypes(ps)
	}
	ps.writeString("{...}")
}

func (le *LambdaExpr) Traverse(fn func(AST) bool) {
	if fn(le) {
		le.Type.Traverse(fn)
	}
}

func (le *LambdaExpr) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(le) {
		return nil
	}
	typ := le.Type.Copy(fn, skip)
	if typ == nil {
		return fn(le)
	}
	le = &LambdaExpr{Type: typ}
	if r := fn(le); r != nil {
		return r
	}
	return le
}

func (le *LambdaExpr) GoString() string {
	return le.goString(0, "")
}

func (le *LambdaExpr) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sLambdaExpr:\n%s", indent, "", field,
		le.Type.goString(indent+2, ""))
}

// ExprList is a list of expressions, typically arguments to a
// function call in an expression.
type ExprList struct {
	Exprs []AST
}

func (el *ExprList) print(ps *printState) {
	ps.printList(el.Exprs, nil)
}

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
}

func (el *ExprList) prec() precedence {
	return precComma
}

// 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 {
		if array, ok := il.Type.(*ArrayType); ok {
			if builtin, ok := array.Element.(*BuiltinType); ok && builtin.Name == "char" {
				if il.printAsString(ps) {
					return
				}
			}
		}
	}

	if il.Type != nil {
		ps.print(il.Type)
	}
	ps.writeByte('{')
	ps.print(il.Exprs)
	ps.writeByte('}')
}

// printAsString tries to print a char array initializer as a string.
// It reports whether it succeeded.
func (il *InitializerList) printAsString(ps *printState) bool {
	exprList, ok := il.Exprs.(*ExprList)
	if !ok {
		return false
	}

	var sb strings.Builder
	sb.WriteByte('"')
	inNumericEscape := false
	for _, e := range exprList.Exprs {
		lit, ok := e.(*Literal)
		if !ok {
			return false
		}
		if lit.Neg {
			return false
		}
		val, err := strconv.Atoi(lit.Val)
		if err != nil || val > 255 {
			return false
		}

		// If we just added a numeric escape,
		// make sure it doesn't get accidentally extended
		// (numeric escapes here are C++ syntax, not Go syntax).
		if inNumericEscape {
			if (val >= '0' && val <= '9') ||
				(val >= 'a' && val <= 'f') ||
				(val >= 'A' && val <= 'F') {
				sb.WriteString(`""`)
			}
		}
		inNumericEscape = false

		switch val {
		case '\a':
			sb.WriteString(`\a`)
		case '\b':
			sb.WriteString(`\b`)
		case '\f':
			sb.WriteString(`\f`)
		case '\n':
			sb.WriteString(`\n`)
		case '\r':
			sb.WriteString(`\r`)
		case '\t':
			sb.WriteString(`\t`)
		case '\v':
			sb.WriteString(`\v`)

		case '"':
			sb.WriteString(`\"`)
		case '\\':
			sb.WriteString(`\\`)

		default:
			if val < 32 || val == 127 {
				const hex = "0123456789ABCDEF"
				sb.WriteByte('\\')
				if val > 7 {
					sb.WriteByte('x')
				}
				if val >= 16 {
					sb.WriteByte(hex[val>>4])
				}
				sb.WriteByte(hex[val&0xf])
				inNumericEscape = true
				break
			}

			sb.WriteByte(byte(val))
		}
	}
	sb.WriteByte('"')

	ps.writeString(sb.String())
	return true
}

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) {
	if !ps.llvmStyle {
		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 {
	TemplateArgs           []AST
	TemplateArgsConstraint AST
	Types                  []AST
	Num                    int
	CallConstraint         AST
}

func (cl *Closure) print(ps *printState) {
	if ps.llvmStyle {
		if cl.Num == 0 {
			ps.writeString("'lambda'")
		} else {
			ps.writeString(fmt.Sprintf("'lambda%d'", cl.Num-1))
		}
	} else {
		ps.writeString("{lambda")
	}
	cl.printTypes(ps)
	if !ps.llvmStyle {
		ps.writeString(fmt.Sprintf("#%d}", cl.Num+1))
	}
}

func (cl *Closure) printTypes(ps *printState) {
	if len(cl.TemplateArgs) > 0 {
		scopes := ps.scopes
		ps.scopes = 0

		ps.writeString("<")
		ps.printList(cl.TemplateArgs, nil)
		ps.writeString(">")

		ps.scopes = scopes
	}

	if cl.TemplateArgsConstraint != nil {
		ps.writeString(" requires ")
		ps.print(cl.TemplateArgsConstraint)
		ps.writeByte(' ')
	}

	ps.startScope('(')
	ps.printList(cl.Types, nil)
	ps.endScope(')')

	if cl.CallConstraint != nil {
		ps.writeString(" requires ")
		ps.print(cl.CallConstraint)
	}
}

func (cl *Closure) Traverse(fn func(AST) bool) {
	if fn(cl) {
		for _, a := range cl.TemplateArgs {
			a.Traverse(fn)
		}
		if cl.TemplateArgsConstraint != nil {
			cl.TemplateArgsConstraint.Traverse(fn)
		}
		for _, t := range cl.Types {
			t.Traverse(fn)
		}
		if cl.CallConstraint != nil {
			cl.CallConstraint.Traverse(fn)
		}
	}
}

func (cl *Closure) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(cl) {
		return nil
	}
	changed := false

	args := make([]AST, len(cl.TemplateArgs))
	for i, a := range cl.TemplateArgs {
		ac := a.Copy(fn, skip)
		if ac == nil {
			args[i] = a
		} else {
			args[i] = ac
			changed = true
		}
	}

	var templateArgsConstraint AST
	if cl.TemplateArgsConstraint != nil {
		templateArgsConstraint = cl.TemplateArgsConstraint.Copy(fn, skip)
		if templateArgsConstraint == nil {
			templateArgsConstraint = cl.TemplateArgsConstraint
		} else {
			changed = true
		}
	}

	types := make([]AST, len(cl.Types))
	for i, t := range cl.Types {
		tc := t.Copy(fn, skip)
		if tc == nil {
			types[i] = t
		} else {
			types[i] = tc
			changed = true
		}
	}

	var callConstraint AST
	if cl.CallConstraint != nil {
		callConstraint = cl.CallConstraint.Copy(fn, skip)
		if callConstraint == nil {
			callConstraint = cl.CallConstraint
		} else {
			changed = true
		}
	}

	if !changed {
		return fn(cl)
	}
	cl = &Closure{
		TemplateArgs:           args,
		TemplateArgsConstraint: templateArgsConstraint,
		Types:                  types,
		Num:                    cl.Num,
		CallConstraint:         callConstraint,
	}
	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 args strings.Builder
	if len(cl.TemplateArgs) == 0 {
		fmt.Fprintf(&args, "%*sTemplateArgs: nil", indent+2, "")
	} else {
		fmt.Fprintf(&args, "%*sTemplateArgs:", indent+2, "")
		for i, a := range cl.TemplateArgs {
			args.WriteByte('\n')
			args.WriteString(a.goString(indent+4, fmt.Sprintf("%d: ", i)))
		}
	}

	var templateArgsConstraint string
	if cl.TemplateArgsConstraint != nil {
		templateArgsConstraint = "\n" + cl.TemplateArgsConstraint.goString(indent+2, "TemplateArgsConstraint: ")
	}

	var types strings.Builder
	if len(cl.Types) == 0 {
		fmt.Fprintf(&types, "%*sTypes: nil", indent+2, "")
	} else {
		fmt.Fprintf(&types, "%*sTypes:", indent+2, "")
		for i, t := range cl.Types {
			types.WriteByte('\n')
			types.WriteString(t.goString(indent+4, fmt.Sprintf("%d: ", i)))
		}
	}

	var callConstraint string
	if cl.CallConstraint != nil {
		callConstraint = "\n" + cl.CallConstraint.goString(indent+2, "CallConstraint: ")
	}

	return fmt.Sprintf("%*s%sClosure: Num: %d\n%s\n%s%s%s", indent, "", field,
		cl.Num, args.String(), templateArgsConstraint, types.String(),
		callConstraint)
}

// StructuredBindings is a structured binding declaration.
type StructuredBindings struct {
	Bindings []AST
}

func (sb *StructuredBindings) print(ps *printState) {
	ps.writeString("[")
	ps.printList(sb.Bindings, nil)
	ps.writeString("]")
}

func (sb *StructuredBindings) Traverse(fn func(AST) bool) {
	if fn(sb) {
		for _, b := range sb.Bindings {
			b.Traverse(fn)
		}
	}
}

func (sb *StructuredBindings) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(sb) {
		return nil
	}
	changed := false
	bindings := make([]AST, len(sb.Bindings))
	for i, b := range sb.Bindings {
		bc := b.Copy(fn, skip)
		if bc == nil {
			bindings[i] = b
		} else {
			bindings[i] = bc
			changed = true
		}
	}
	if !changed {
		return fn(sb)
	}
	sb = &StructuredBindings{Bindings: bindings}
	if r := fn(sb); r != nil {
		return r
	}
	return sb
}

func (sb *StructuredBindings) GoString() string {
	return sb.goString(0, "")
}

func (sb *StructuredBindings) goString(indent int, field string) string {
	var strb strings.Builder
	fmt.Fprintf(&strb, "%*s%sStructuredBinding:", indent, "", field)
	for _, b := range sb.Bindings {
		strb.WriteByte('\n')
		strb.WriteString(b.goString(indent+2, ""))
	}
	return strb.String()
}

// UnnamedType is an unnamed type, that just has an index.
type UnnamedType struct {
	Num int
}

func (ut *UnnamedType) print(ps *printState) {
	if ps.llvmStyle {
		if ut.Num == 0 {
			ps.writeString("'unnamed'")
		} else {
			ps.writeString(fmt.Sprintf("'unnamed%d'", ut.Num-1))
		}
	} else {
		ps.writeString(fmt.Sprintf("{unnamed type#%d}", ut.Num+1))
	}
}

func (ut *UnnamedType) Traverse(fn func(AST) bool) {
	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)
}

// UnnamedEnum is an unnamed enum type.
type UnnamedEnum struct {
	Underlying AST
	Name       AST
}

func (ue *UnnamedEnum) print(ps *printState) {
	ps.writeString("{enum:")
	ps.print(ue.Underlying)
	ps.writeByte('{')
	ps.print(ue.Name)
	ps.writeString("}}")
}

func (ue *UnnamedEnum) Traverse(fn func(AST) bool) {
	if fn(ue) {
		ue.Underlying.Traverse(fn)
		ue.Name.Traverse(fn)
	}
}

func (ue *UnnamedEnum) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(ue) {
		return nil
	}
	underlying := ue.Underlying.Copy(fn, skip)
	name := ue.Name.Copy(fn, skip)
	if underlying == nil && name == nil {
		return fn(ue)
	}
	if underlying == nil {
		underlying = ue.Underlying
	}
	if name == nil {
		name = ue.Name
	}
	ue = &UnnamedEnum{Underlying: underlying, Name: name}
	if r := fn(ue); r != nil {
		return r
	}
	return ue
}

func (ue *UnnamedEnum) GoString() string {
	return ue.goString(0, "")
}

func (ue *UnnamedEnum) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sUnnamedEnum:\n%s\n%s", indent, "", field,
		ue.Underlying.goString(indent+2, "Underlying: "),
		ue.Name.goString(indent+2, "Name: "))
}

// 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)
	if ps.llvmStyle {
		ps.writeByte(' ')
		ps.startScope('(')
		ps.writeString(c.Suffix)
		ps.endScope(')')
	} else {
		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) {
	prefix := s.Prefix
	if ps.llvmStyle {
		switch prefix {
		case "TLS wrapper function for ":
			prefix = "thread-local wrapper routine for "
		case "TLS init function for ":
			prefix = "thread-local initialization routine for "
		}
	}
	ps.writeString(prefix)
	ps.print(s.Val)
}

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: "))
}

// EnableIf is used by clang for an enable_if attribute.
type EnableIf struct {
	Type AST
	Args []AST
}

func (ei *EnableIf) print(ps *printState) {
	ps.print(ei.Type)
	ps.writeString(" [enable_if:")
	ps.printList(ei.Args, nil)
	ps.writeString("]")
}

func (ei *EnableIf) Traverse(fn func(AST) bool) {
	if fn(ei) {
		ei.Type.Traverse(fn)
		for _, a := range ei.Args {
			a.Traverse(fn)
		}
	}
}

func (ei *EnableIf) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(ei) {
		return nil
	}
	typ := ei.Type.Copy(fn, skip)
	argsChanged := false
	args := make([]AST, len(ei.Args))
	for i, a := range ei.Args {
		ac := a.Copy(fn, skip)
		if ac == nil {
			args[i] = a
		} else {
			args[i] = ac
			argsChanged = true
		}
	}
	if typ == nil && !argsChanged {
		return fn(ei)
	}
	if typ == nil {
		typ = ei.Type
	}
	ei = &EnableIf{Type: typ, Args: args}
	if r := fn(ei); r != nil {
		return r
	}
	return ei
}

func (ei *EnableIf) GoString() string {
	return ei.goString(0, "")
}

func (ei *EnableIf) goString(indent int, field string) string {
	var args string
	if len(ei.Args) == 0 {
		args = fmt.Sprintf("%*sArgs: nil", indent+2, "")
	} else {
		args = fmt.Sprintf("%*sArgs:", indent+2, "")
		for i, a := range ei.Args {
			args += "\n"
			args += a.goString(indent+4, fmt.Sprintf("%d: ", i))
		}
	}
	return fmt.Sprintf("%*s%sEnableIf:\n%s\n%s", indent, "", field,
		ei.Type.goString(indent+2, "Type: "), args)
}

// ModuleName is a C++20 module.
type ModuleName struct {
	Parent      AST
	Name        AST
	IsPartition bool
}

func (mn *ModuleName) print(ps *printState) {
	if mn.Parent != nil {
		ps.print(mn.Parent)
	}
	if mn.IsPartition {
		ps.writeByte(':')
	} else if mn.Parent != nil {
		ps.writeByte('.')
	}
	ps.print(mn.Name)
}

func (mn *ModuleName) Traverse(fn func(AST) bool) {
	if fn(mn) {
		if mn.Parent != nil {
			mn.Parent.Traverse(fn)
		}
		mn.Name.Traverse(fn)
	}
}

func (mn *ModuleName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(mn) {
		return nil
	}
	var parent AST
	if mn.Parent != nil {
		parent = mn.Parent.Copy(fn, skip)
	}
	name := mn.Name.Copy(fn, skip)
	if parent == nil && name == nil {
		return fn(mn)
	}
	if parent == nil {
		parent = mn.Parent
	}
	if name == nil {
		name = mn.Name
	}
	mn = &ModuleName{Parent: parent, Name: name, IsPartition: mn.IsPartition}
	if r := fn(mn); r != nil {
		return r
	}
	return mn
}

func (mn *ModuleName) GoString() string {
	return mn.goString(0, "")
}

func (mn *ModuleName) goString(indent int, field string) string {
	var parent string
	if mn.Parent == nil {
		parent = fmt.Sprintf("%*sParent: nil", indent+2, "")
	} else {
		parent = mn.Parent.goString(indent+2, "Parent: ")
	}
	return fmt.Sprintf("%*s%sModuleName: IsPartition: %t\n%s\n%s", indent, "", field,
		mn.IsPartition, parent,
		mn.Name.goString(indent+2, "Name: "))
}

// ModuleEntity is a name inside a module.
type ModuleEntity struct {
	Module AST
	Name   AST
}

func (me *ModuleEntity) print(ps *printState) {
	ps.print(me.Name)
	ps.writeByte('@')
	ps.print(me.Module)
}

func (me *ModuleEntity) Traverse(fn func(AST) bool) {
	if fn(me) {
		me.Module.Traverse(fn)
		me.Name.Traverse(fn)
	}
}

func (me *ModuleEntity) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(me) {
		return nil
	}
	module := me.Module.Copy(fn, skip)
	name := me.Name.Copy(fn, skip)
	if module == nil && name == nil {
		return fn(me)
	}
	if module == nil {
		module = me.Module
	}
	if name == nil {
		name = me.Name
	}
	me = &ModuleEntity{Module: module, Name: name}
	if r := fn(me); r != nil {
		return r
	}
	return me
}

func (me *ModuleEntity) GoString() string {
	return me.goString(0, "")
}

func (me *ModuleEntity) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sModuleEntity:\n%s\n%s", indent, "", field,
		me.Module.goString(indent+2, "Module: "),
		me.Name.goString(indent+2, "Name: "))
}

// Friend is a member like friend name.
type Friend struct {
	Name AST
}

func (f *Friend) print(ps *printState) {
	if ps.llvmStyle {
		ps.writeString("friend ")
	}
	ps.print(f.Name)
	if !ps.llvmStyle {
		ps.writeString("[friend]")
	}
}

func (f *Friend) Traverse(fn func(AST) bool) {
	if fn(f) {
		f.Name.Traverse(fn)
	}
}

func (f *Friend) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(f) {
		return nil
	}
	name := f.Name.Copy(fn, skip)
	if name == nil {
		return fn(f)
	}
	f = &Friend{Name: name}
	if r := fn(f); r != nil {
		return r
	}
	return f
}

func (f *Friend) GoString() string {
	return f.goString(0, "")
}

func (f *Friend) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sFriend:\n%s", indent, "", field,
		f.Name.goString(indent+2, "Name: "))
}

// Constraint represents an AST with a constraint.
// ForTemplateArgs is true if this constraint was found at the
// end of a list of template arguments. We need that because
// in LLVM style we don't print constraints of that sort.
type Constraint struct {
	Name            AST
	Requires        AST
	ForTemplateArgs bool
}

func (c *Constraint) print(ps *printState) {
	ps.print(c.Name)

	// For LLVM style skip the constraint on a template.
	if ps.llvmStyle && c.ForTemplateArgs {
		return
	}

	ps.writeString(" requires ")
	ps.print(c.Requires)
}

func (c *Constraint) Traverse(fn func(AST) bool) {
	if fn(c) {
		c.Name.Traverse(fn)
		c.Requires.Traverse(fn)
	}
}

func (c *Constraint) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(c) {
		return nil
	}
	name := c.Name.Copy(fn, skip)
	requires := c.Requires.Copy(fn, skip)
	if name == nil && requires == nil {
		return fn(c)
	}
	if name == nil {
		name = c.Name
	}
	if requires == nil {
		requires = c.Requires
	}
	c = &Constraint{
		Name:            name,
		Requires:        requires,
		ForTemplateArgs: c.ForTemplateArgs,
	}
	if r := fn(c); r != nil {
		return r
	}
	return c
}

func (c *Constraint) GoString() string {
	return c.goString(0, "")
}

func (c *Constraint) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sConstraint: ForTemplateArgs: %t\n%s\n%s", indent, "", field,
		c.ForTemplateArgs,
		c.Name.goString(indent+2, "Name: "),
		c.Requires.goString(indent+2, "Requires: "))
}

// RequiresExpr is a C++20 requires expression.
type RequiresExpr struct {
	Params       []AST
	Requirements []AST
}

func (re *RequiresExpr) print(ps *printState) {
	ps.writeString("requires")
	if len(re.Params) > 0 {
		ps.writeByte(' ')
		ps.startScope('(')
		ps.printList(re.Params, nil)
		ps.endScope(')')
	}
	ps.writeByte(' ')
	ps.startScope('{')
	for _, req := range re.Requirements {
		ps.print(req)
	}
	ps.writeByte(' ')
	ps.endScope('}')
}

func (re *RequiresExpr) Traverse(fn func(AST) bool) {
	if fn(re) {
		for _, p := range re.Params {
			p.Traverse(fn)
		}
		for _, r := range re.Requirements {
			r.Traverse(fn)
		}
	}
}

func (re *RequiresExpr) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(re) {
		return nil
	}

	changed := false

	var params []AST
	if len(re.Params) > 0 {
		params = make([]AST, len(re.Params))
		for i, p := range re.Params {
			pc := p.Copy(fn, skip)
			if pc == nil {
				params[i] = p
			} else {
				params[i] = pc
				changed = true
			}
		}
	}

	requirements := make([]AST, len(re.Requirements))
	for i, r := range re.Requirements {
		rc := r.Copy(fn, skip)
		if rc == nil {
			requirements[i] = r
		} else {
			requirements[i] = rc
			changed = true
		}
	}

	if !changed {
		return fn(re)
	}

	re = &RequiresExpr{Params: params, Requirements: requirements}
	if r := fn(re); r != nil {
		return r
	}
	return re
}

func (re *RequiresExpr) GoString() string {
	return re.goString(0, "")
}

func (re *RequiresExpr) goString(indent int, field string) string {
	var params strings.Builder
	if len(re.Params) == 0 {
		fmt.Fprintf(&params, "%*sParams: nil", indent+2, "")
	} else {
		fmt.Fprintf(&params, "%*sParams:", indent+2, "")
		for i, p := range re.Params {
			params.WriteByte('\n')
			params.WriteString(p.goString(indent+4, fmt.Sprintf("%d: ", i)))
		}
	}

	var requirements strings.Builder
	fmt.Fprintf(&requirements, "%*sRequirements:", indent+2, "")
	for i, r := range re.Requirements {
		requirements.WriteByte('\n')
		requirements.WriteString(r.goString(indent+4, fmt.Sprintf("%d: ", i)))
	}

	return fmt.Sprintf("%*s%sRequirements:\n%s\n%s", indent, "", field,
		params.String(), requirements.String())
}

// ExprRequirement is a simple requirement in a requires expression.
// This is an arbitrary expression.
type ExprRequirement struct {
	Expr     AST
	Noexcept bool
	TypeReq  AST
}

func (er *ExprRequirement) print(ps *printState) {
	ps.writeByte(' ')
	if er.Noexcept || er.TypeReq != nil {
		ps.startScope('{')
	}
	ps.print(er.Expr)
	if er.Noexcept || er.TypeReq != nil {
		ps.endScope('}')
	}
	if er.Noexcept {
		ps.writeString(" noexcept")
	}
	if er.TypeReq != nil {
		ps.writeString(" -> ")
		ps.print(er.TypeReq)
	}
	ps.writeByte(';')
}

func (er *ExprRequirement) Traverse(fn func(AST) bool) {
	if fn(er) {
		er.Expr.Traverse(fn)
		if er.TypeReq != nil {
			er.TypeReq.Traverse(fn)
		}
	}
}

func (er *ExprRequirement) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(er) {
		return nil
	}
	expr := er.Expr.Copy(fn, skip)
	var typeReq AST
	if er.TypeReq != nil {
		typeReq = er.TypeReq.Copy(fn, skip)
	}
	if expr == nil && typeReq == nil {
		return fn(er)
	}
	if expr == nil {
		expr = er.Expr
	}
	if typeReq == nil {
		typeReq = er.TypeReq
	}
	er = &ExprRequirement{Expr: expr, TypeReq: typeReq}
	if r := fn(er); r != nil {
		return r
	}
	return er
}

func (er *ExprRequirement) GoString() string {
	return er.goString(0, "")
}

func (er *ExprRequirement) goString(indent int, field string) string {
	var typeReq string
	if er.TypeReq != nil {
		typeReq = "\n" + er.TypeReq.goString(indent+2, "TypeReq: ")
	}

	return fmt.Sprintf("%*s%sExprRequirement: Noexcept: %t\n%s%s", indent, "", field,
		er.Noexcept,
		er.Expr.goString(indent+2, "Expr: "),
		typeReq)
}

// TypeRequirement is a type requirement in a requires expression.
type TypeRequirement struct {
	Type AST
}

func (tr *TypeRequirement) print(ps *printState) {
	ps.writeString(" typename ")
	ps.print(tr.Type)
	ps.writeByte(';')
}

func (tr *TypeRequirement) Traverse(fn func(AST) bool) {
	if fn(tr) {
		tr.Type.Traverse(fn)
	}
}

func (tr *TypeRequirement) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(tr) {
		return nil
	}
	typ := tr.Type.Copy(fn, skip)
	if typ == nil {
		return fn(tr)
	}
	tr = &TypeRequirement{Type: typ}
	if r := fn(tr); r != nil {
		return r
	}
	return tr
}

func (tr *TypeRequirement) GoString() string {
	return tr.goString(0, "")
}

func (tr *TypeRequirement) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sTypeRequirement:\n%s", indent, "", field,
		tr.Type.goString(indent+2, ""))
}

// NestedRequirement is a nested requirement in a requires expression.
type NestedRequirement struct {
	Constraint AST
}

func (nr *NestedRequirement) print(ps *printState) {
	ps.writeString(" requires ")
	ps.print(nr.Constraint)
	ps.writeByte(';')
}

func (nr *NestedRequirement) Traverse(fn func(AST) bool) {
	if fn(nr) {
		nr.Constraint.Traverse(fn)
	}
}

func (nr *NestedRequirement) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(nr) {
		return nil
	}
	constraint := nr.Constraint.Copy(fn, skip)
	if constraint == nil {
		return fn(nr)
	}
	nr = &NestedRequirement{Constraint: constraint}
	if r := fn(nr); r != nil {
		return r
	}
	return nr
}

func (nr *NestedRequirement) GoString() string {
	return nr.goString(0, "")
}

func (nr *NestedRequirement) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sNestedRequirement:\n%s", indent, "", field,
		nr.Constraint.goString(indent+2, ""))
}

// ExplicitObjectParameter represents a C++23 explicit object parameter.
type ExplicitObjectParameter struct {
	Base AST
}

func (eop *ExplicitObjectParameter) print(ps *printState) {
	ps.writeString("this ")
	ps.print(eop.Base)
}

func (eop *ExplicitObjectParameter) Traverse(fn func(AST) bool) {
	if fn(eop) {
		eop.Base.Traverse(fn)
	}
}

func (eop *ExplicitObjectParameter) Copy(fn func(AST) AST, skip func(AST) bool) AST {
	if skip(eop) {
		return nil
	}
	base := eop.Base.Copy(fn, skip)
	if base == nil {
		return fn(eop)
	}
	eop = &ExplicitObjectParameter{Base: base}
	if r := fn(eop); r != nil {
		return r
	}
	return eop
}

func (eop *ExplicitObjectParameter) GoString() string {
	return eop.goString(0, "")
}

func (eop *ExplicitObjectParameter) goString(indent int, field string) string {
	return fmt.Sprintf("%*s%sExplicitObjectParameter:\n%s", indent, "", field,
		eop.Base.goString(indent+2, ""))
}

// 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:
		for _, a := range a.Args {
			if !ps.isEmpty(a) {
				return false
			}
		}
		return true
	case *ExprList:
		return len(a.Exprs) == 0
	case *PackExpansion:
		return a.Pack != nil && ps.isEmpty(a.Base)
	default:
		return false
	}
}


================================================
FILE: ast_test.go
================================================
// 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 (
	"fmt"
	"testing"
)

func TestASTToString(t *testing.T) {
	var tests = []struct {
		input     AST
		want      string
		formatted string
	}{
		{
			&Qualified{Scope: &Name{Name: "s"}, Name: &Name{Name: "C"}},
			"s::C",
			`Qualified:
  Scope: s
  Name: C`,
		},
		{
			&Typed{Name: &Name{Name: "v"}, Type: &BuiltinType{"int"}},
			"int v",
			`Typed:
  Name: v
  Type: BuiltinType: int`,
		},
	}

	for i, test := range tests {
		if got := ASTToString(test.input); got != test.want {
			t.Errorf("ASTToString of test %d == %s, want %s", i, test.input, test.want)
		}
		if got := fmt.Sprintf("%#v", test.input); got != test.formatted {
			t.Errorf("Formatted test %d == %s, want %s", i, got, test.formatted)
		}
	}
}


================================================
FILE: c++filt.go
================================================
// 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.

//go:build ignore
// +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 noTemplateParams = flag.Bool("T", false, "Do not display template parameters")
var noEnclosingParams = flag.Bool("e", false, "Do not display enclosing parameters")
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")
var llvm = flag.Bool("llvm", false, "Demangle strings in LLVM style")
var maxLen = flag.Int("m", 0, "Maximum length as power of 2, between 1 and 30")

// 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))
	scanner.Buffer(nil, 1<<30)
	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)
		}
	}
	if err := scanner.Err(); 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 *noTemplateParams {
		options = append(options, demangle.NoTemplateParams)
	}
	if *noEnclosingParams {
		options = append(options, demangle.NoEnclosingParams)
	}
	if !*noVerbose {
		options = append(options, demangle.Verbose)
	}
	if *llvm {
		options = append(options, demangle.LLVMStyle)
	}
	if *maxLen > 0 {
		options = append(options, demangle.MaxLength(*maxLen))
	}
	return options
}


================================================
FILE: cases_test.go
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package demangle

import (
	"bufio"
	"io"
	"os"
	"strings"
	"testing"
)

// casesExpectedFailures is a list of exceptions from cases that we
// don't expect to pass.  This is to let us incrementally fix them
// over time.
var casesExpectedFailures = map[string]bool{
	"_ZSteqIcEN9__gnu_cxx11__enable_ifIXsr9__is_charIT_EE7__valueEbE6__typeERKSbIS2_St11char_traitsIS2_ESaIS2_EESA_": true,
	"_Z1fPU11objcproto1A11objc_object":             true,
	"_Z1fPKU11objcproto1A7NSArray":                 true,
	"_ZNK1AIJ1Z1Y1XEEcv1BIJDpPT_EEIJS2_S1_S0_EEEv": true,
	"_ZNK3Ncr6Silver7Utility6detail12CallOnThreadIZ53-[DeploymentSetupController handleManualServerEntry:]E3$_5EclIJEEEDTclclL_ZNS2_4getTIS4_EERT_vEEspclsr3stdE7forwardIT_Efp_EEEDpOSA_": true,
	"_Z1fIJicEEvDp7MuncherIAstT__S1_E":                 true,
	"_ZN5test31aINS_1XEMS1_PiEEvT_T0_DTdsfL0p_fL0p0_E": true,
	"_Z1fPU3AS1KiS0_":                                  true,
	"_Z1pILb1EEiM1SKDOT_EFivRE":                        true,
	"_Z1pIJicfEEiM1SVKDwDpT_EFivOE":                    true,
	"_ZZ18test_assign_throwsI20small_throws_on_copyLb0EEvvENKUlRNSt3__13anyEOT_E_clIRS0_EEDaS3_S5_": true,
	"_ZN1Scv7MuncherIJDpPT_EEIJFivEA_iEEEv":                                                         true,
	"_Z2f8IiJ8identityIiES0_IfEEEvRAsPiDpT0_T_DpNS3_4typeEE_i":                                      true,
	"_ZZ11inline_funcvENKUlTyTyT_T0_E_clIiiEEDaS_S0_":                                               true,
	"_ZZ11inline_funcvENKUlTyTyT_T1_T0_E_clIiiiEEDaS_S0_S1_":                                        true,

	"_Z1fIXfLpm1x1yEEvv": true,
	"_Z1fIXfLds1x1yEEvv": true,
}

// caseExceptions is a list of exceptions from the LLVM list that we
// do not handle the same as the LLVM demangler.  We keep a list of
// exceptions so that we can use an exact copy of the test cases.  We
// map to an empty string if we expect a demangling failure; this
// differs from caseExpectedFailures in that we've decided that we
// intentionally should not demangle this case.  Otherwise this maps
// to the expected demangling.
var casesExceptions = map[string]string{
	"_ZN1XIZ1fIiEvOT_EUlOT_DpT0_E_EclIJEEEvDpT_": "void X<void f<int>(int&&)::'lambda'(auto&&, auto)>::operator()<>()",
	"_ZN1XIZ1fIiEvOT_EUlS2_DpT0_E_EclIJEEEvDpT_": "void X<void f<int>(int&&)::'lambda'(auto&&, auto)>::operator()<>()",
	"_Z1h1XIJZ1fIiEDaOT_E1AZ1gIdEDaS2_E1BEE":     "h(X<auto f<int>(int&&)::A, auto g<double>(double&&)::B>)",
	"_Zcv1BIRT_EIS1_E":                           "",

	// For the next four test cases it seems to me that
	// <int, int>(int) is more correct than <int, int>(auto).
	// It depends on how we handle a template parameter in
	// and out of a lambda expression.
	"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E_clIiiEEDaS3_Q1CIDtfp_EE":        "auto void test7::f<int>()::'lambda'<typename $T> requires C<T> && C<TL0_> (auto)::operator()<int, int>(int) const requires C<decltype(fp)>",
	"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E0_clIiiEEDaS3_Qaa1CIDtfp_EELb1E": "auto void test7::f<int>()::'lambda0'<typename $T> requires C<T> && C<TL0_> (auto)::operator()<int, int>(int) const requires C<decltype(fp)> && true",
	"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E1_clIiiEEDaS3_Q1CIDtfp_EE":       "auto void test7::f<int>()::'lambda1'<typename $T> requires C<T> && C<TL0_> (auto)::operator()<int, int>(int) const requires C<decltype(fp)>",
	"_ZZN5test71fIiEEvvENKUlTyT0_E_clIiiEEDaS1_":                                     "auto void test7::f<int>()::'lambda'<typename $T>(auto)::operator()<int, int>(int) const",
}

func TestCases(t *testing.T) {
	t.Parallel()

	cases := readCases(t)

	expectedErrors := 0
	expectedDifferent := 0
	found := make(map[string]bool)
	for _, test := range cases {
		expectedFail := casesExpectedFailures[test[0]]
		exception, haveException := casesExceptions[test[0]]
		if expectedFail && haveException {
			t.Errorf("test case error: %s in both expectedFailures and exceptions", test[0])
		}
		want := test[1]
		if haveException && exception != "" {
			if want == exception {
				t.Errorf("test case error: %s exception is expected result", test[0])
			}
			want = exception
		}

		// We don't strip an extra underscore.
		testStr := test[0]
		if strings.HasPrefix(testStr, "__Z") || strings.HasPrefix(testStr, "____Z") {
			testStr = testStr[1:]
		}

		// We don't demangle plain types, so just skip them.
		if !strings.HasPrefix(testStr, "_") {
			continue
		}

		if got, err := ToString(testStr, LLVMStyle); err != nil {
			if expectedFail || (haveException && exception == "") {
				t.Logf("demangling %s: expected failure: error %v", test[0], err)
				if expectedFail {
					expectedErrors++
					found[test[0]] = true
				}
			} else {
				t.Errorf("demangling %s: unexpected error %v", test[0], err)
			}
		} else if got != want {
			if expectedFail {
				t.Logf("demangling %s: expected failure: got %s, want %s", test[0], got, want)
				expectedDifferent++
				found[test[0]] = true
			} else if haveException && exception == "" {
				t.Errorf("demangling %s: expected to fail, but succeeded with %s", test[0], got)
			} else {
				t.Errorf("demangling %s: got %s, want %s", test[0], got, want)
			}
		} else if expectedFail || (haveException && exception == "") {
			t.Errorf("demangling %s: expected to fail, but succeeded with %s", test[0], got)
			if expectedFail {
				found[test[0]] = true
			}
		}
	}
	if len(found) != len(casesExpectedFailures) {
		for expected := range casesExpectedFailures {
			if !found[expected] {
				t.Errorf("expected %s to fail but did not see it", expected)
			}
		}
		for f := range found {
			if !casesExpectedFailures[f] {
				t.Errorf("internal error: found failing but unexpected %s", f)
			}
		}
	}
	if expectedDifferent > 0 {
		t.Logf("%d different demanglings out of %d cases", expectedDifferent, len(cases))
	}
	if expectedErrors > 0 {
		t.Logf("%d expected failures out of %d cases", expectedErrors, len(cases))
	}
}

// readCases reads the LLVM test cases from DemangleTestCases.inc.
// That file is copied from
//
//	llvm-project/libcxxabi/test/DemangleTestCases.inc
//
// That file has no license, but LLVM in general has the license text:
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// This file is only used for testing and does not form part of the
// demangle package when it is used by other code.
//
// The file does not contain any code, only test cases and comments.
func readCases(t testing.TB) [][2]string {
	const fn = "testdata/DemangleTestCases.inc"
	f, err := os.Open(fn)
	if err != nil {
		t.Fatal(err)
	}
	defer f.Close()

	var cases [][2]string
	r := bufio.NewReader(f)
	lineno := 1
	for {
		b, atEOF := readCasesUnquotedByte(t, r, fn, &lineno)
		if atEOF {
			break
		}
		if b != '{' {
			t.Fatalf("%s:%d: got %c, want {", fn, lineno, b)
		}

		s1 := readCasesString(t, r, fn, &lineno)

		for {
			b = readCasesUnquotedByteNoEOF(t, r, fn, &lineno)
			if b == ',' {
				break
			}
			if b != '"' {
				t.Fatalf("%s:%d: got %c, want ,", fn, lineno, b)
			}

			r.UnreadByte()
			s1 += readCasesString(t, r, fn, &lineno)
		}

		s2 := readCasesString(t, r, fn, &lineno)

		for {
			b = readCasesUnquotedByteNoEOF(t, r, fn, &lineno)
			if b == '}' {
				break
			}
			if b != '"' {
				t.Fatalf("%s:%d: got %c, want }", fn, lineno, b)
			}

			r.UnreadByte()
			s2 += readCasesString(t, r, fn, &lineno)
		}

		b = readCasesUnquotedByteNoEOF(t, r, fn, &lineno)
		if b != ',' {
			t.Fatalf("%s:%d: got %c, want ,", fn, lineno, b)
		}

		cases = append(cases, [2]string{s1, s2})
	}

	return cases
}

// readCasesString reads a quoted string from the cases file.
func readCasesString(t testing.TB, r *bufio.Reader, fn string, lineno *int) string {
	b, atEOF := readCasesUnquotedByte(t, r, fn, lineno)
	if atEOF {
		t.Fatalf(`%s:%d: got EOF, want "`, fn, *lineno)
	}
	if b != '"' {
		t.Fatalf(`%s:%d: got %c, want "`, fn, *lineno, b)
	}

	var sb strings.Builder
	for {
		b = readCasesByteNoEOF(t, r, fn, *lineno)
		if b == '"' {
			break
		}
		if b != '\\' {
			sb.WriteByte(b)
			continue
		}

		b = readCasesByteNoEOF(t, r, fn, *lineno)
		switch b {
		case '"', '\'', '?', '\\':
			sb.WriteByte(b)
			continue
		case 't':
			sb.WriteByte('\t')
			continue

		case '0', '1', '2', '3', '4', '5', '6', '7':
			val := b - '0'
		octalLoop:
			for {
				b = readCasesByteNoEOF(t, r, fn, *lineno)
				switch b {
				case '0', '1', '2', '3', '4', '5', '6', '7':
					val <<= 3
					val += b - '0'
				default:
					r.UnreadByte()
					break octalLoop
				}
			}
			sb.WriteByte(val)

		case 'x':
			val := byte(0)
			seen := false
		hexLoop:
			for {
				b = readCasesByteNoEOF(t, r, fn, *lineno)
				bval := byte(0)
				switch b {
				case '0', '1', '2', '3', '4', '5', '6', '7':
					bval = b - '0'
				case 'A', 'B', 'C', 'D', 'E', 'F':
					bval = b - 'A'
				case 'a', 'b', 'c', 'd', 'e', 'f':
					bval = b - 'a'
				default:
					r.UnreadByte()
					break hexLoop
				}
				val <<= 4
				val += bval
				seen = true
			}
			if !seen {
				t.Fatalf(`%s:%d: no hex digits after \x`, fn, *lineno)
			}
			sb.WriteByte(val)

		default:
			t.Fatalf(`%s:%d: unexpected escape sequence \%c in string`, fn, *lineno, b)
		}
	}

	return sb.String()
}

// readCasesUnquotedByte reads a byte from the cases file,
// where the byte is not in a quoted string.
// This skips comments and whitespace.
// The bool result reports whether we are at EOF.
func readCasesUnquotedByte(t testing.TB, r *bufio.Reader, fn string, lineno *int) (byte, bool) {
	for {
		b, atEOF := readCasesByte(t, r, fn, *lineno)
		if atEOF {
			return 0, true
		}
		if b == ' ' || b == '\t' {
			continue
		}
		if b == '\n' {
			*lineno++
			continue
		}
		if b == '/' {
			b, atEOF = readCasesByte(t, r, fn, *lineno)
			if atEOF || b != '/' {
				t.Fatalf("%s:%d: unexpected single /", fn, *lineno)
			}
			for {
				_, err := r.ReadSlice('\n')
				if err == nil {
					*lineno++
					break
				}
				switch err {
				case bufio.ErrBufferFull:
				case io.EOF:
					return 0, true
				default:
					t.Fatalf("%s:%d: %v", fn, *lineno, err)
				}
			}
			continue
		}

		return b, false
	}
}

// readCasesUnquotedByteNoEOF is like readCasesUnquotedByte,
// but fails on EOF.
func readCasesUnquotedByteNoEOF(t testing.TB, r *bufio.Reader, fn string, lineno *int) byte {
	b, atEOF := readCasesUnquotedByte(t, r, fn, lineno)
	if atEOF {
		t.Helper()
		t.Fatalf("%s:%d: unexpected EOF", fn, *lineno)
	}
	return b
}

// readCasesByte reads a byte from the cases file.
// The bool result reports whether we are at EOF.
func readCasesByte(t testing.TB, r *bufio.Reader, fn string, lineno int) (byte, bool) {
	b, err := r.ReadByte()
	if err != nil {
		if err == io.EOF {
			return 0, true
		}
		t.Helper()
		t.Fatalf("%s:%d: %v", fn, lineno, err)
	}
	return b, false
}

// readCasesByteNoEOF is like readCasesByte, but fails on EOF.
func readCasesByteNoEOF(t testing.TB, r *bufio.Reader, fn string, lineno int) byte {
	b, atEOF := readCasesByte(t, r, fn, lineno)
	if atEOF {
		t.Helper()
		t.Fatalf("%s:%d: unexpected EOF", fn, lineno)
	}
	return b
}


================================================
FILE: demangle.go
================================================
// 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++ and Rust symbol names.
// This package recognizes names that were mangled according to the C++ ABI
// defined at http://codesourcery.com/cxx-abi/ and the Rust ABI
// defined at
// https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html
//
// Most programs will want to call Filter or ToString.
package demangle

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++ or Rust mangled name")

// Option is the type of demangler options.
type Option int

const (
	// The NoParams option disables demangling of function parameters.
	// It only omits the parameters of the function name being demangled,
	// not the parameter types of other functions that may be mentioned.
	// Using the option will speed up the demangler and cause it to
	// use less memory.
	NoParams Option = iota

	// The NoTemplateParams option disables demangling of template parameters.
	// This applies to both C++ and Rust.
	NoTemplateParams

	// The NoEnclosingParams option disables demangling of the function
	// parameter types of the enclosing function when demangling a
	// local name defined within a function.
	NoEnclosingParams

	// The NoClones option disables inclusion of clone suffixes.
	// NoParams implies NoClones.
	NoClones

	// The NoRust option disables demangling of old-style Rust
	// mangled names, which can be confused with C++ style mangled
	// names. New style Rust mangled names are still recognized.
	NoRust

	// The Verbose option turns on more verbose demangling.
	Verbose

	// LLVMStyle tries to translate an AST to a string in the
	// style of the LLVM demangler. This does not affect
	// the parsing of the AST, only the conversion of the AST
	// to a string.
	LLVMStyle
)

// maxLengthShift is how we shift the MaxLength value.
const maxLengthShift = 16

// maxLengthMask is a mask for the maxLength value.
const maxLengthMask = 0x1f << maxLengthShift

// MaxLength returns an Option that limits the maximum length of a
// demangled string. The maximum length is expressed as a power of 2,
// so a value of 1 limits the returned string to 2 characters, and
// a value of 16 limits the returned string to 65,536 characters.
// The value must be between 1 and 30.
func MaxLength(pow int) Option {
	if pow <= 0 || pow > 30 {
		panic("demangle: invalid MaxLength value")
	}
	return Option(pow << maxLengthShift)
}

// isMaxLength reports whether an Option holds a maximum length.
func isMaxLength(opt Option) bool {
	return opt&maxLengthMask != 0
}

// maxLength returns the maximum length stored in an Option.
func maxLength(opt Option) int {
	return 1 << ((opt & maxLengthMask) >> maxLengthShift)
}

// Filter demangles a C++ or Rust symbol name,
// returning the human-readable C++ or Rust name.
// If any error occurs during demangling, the input string is returned.
func Filter(name string, options ...Option) string {
	ret, err := ToString(name, options...)
	if err != nil {
		return name
	}
	return ret
}

// ToString demangles a C++ or Rust symbol name,
// returning a human-readable C++ or Rust name or an error.
// If the name does not appear to be a C++ or Rust symbol name at all,
// the error will be ErrNotMangledName.
func ToString(name string, options ...Option) (string, error) {
	if strings.HasPrefix(name, "_R") {
		return rustToString(name, options)
	}

	// Check for an old-style Rust mangled name.
	// It starts with _ZN and ends with "17h" followed by 16 hex digits
	// followed by "E" followed by an optional suffix starting with "."
	// (which we ignore).
	if strings.HasPrefix(name, "_ZN") {
		rname := name
		if pos := strings.LastIndex(rname, "E."); pos > 0 {
			rname = rname[:pos+1]
		}
		if strings.HasSuffix(rname, "E") && len(rname) > 23 && rname[len(rname)-20:len(rname)-17] == "17h" {
			noRust := false
			for _, o := range options {
				if o == NoRust {
					noRust = true
					break
				}
			}
			if !noRust {
				s, ok := oldRustToString(rname, options)
				if ok {
					return s, nil
				}
			}
		}
	}

	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.
// This function does not currently support Rust symbol names.
func ToAST(name string, options ...Option) (AST, error) {
	if strings.HasPrefix(name, "_Z") {
		a, err := doDemangle(name[2:], options...)
		return a, adjustErr(err, 2)
	}

	if strings.HasPrefix(name, "___Z") {
		// clang extensions
		block := strings.LastIndex(name, "_block_invoke")
		if block == -1 {
			return nil, ErrNotMangledName
		}
		a, err := doDemangle(name[4:block], options...)
		if err != nil {
			return a, adjustErr(err, 4)
		}
		name = strings.TrimPrefix(name[block:], "_block_invoke")
		if len(name) > 0 && name[0] == '_' {
			name = name[1:]
		}
		for len(name) > 0 && isDigit(name[0]) {
			name = name[1:]
		}
		if len(name) > 0 && name[0] != '.' {
			return nil, errors.New("unparsed characters at end of mangled name")
		}
		a = &Special{Prefix: "invocation function for block in ", Val: a}
		return a, nil
	}

	const ctorDtorPrefix = "_GLOBAL_"
	if strings.HasPrefix(name, ctorDtorPrefix) {
		// 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:i], options[i+1:]...)
			} else {
				i++
			}
		}
		a, err := globalCDtorName(name[len(ctorDtorPrefix):], options...)
		return a, adjustErr(err, len(ctorDtorPrefix))
	}

	const allocTokenPrefix = "__alloc_token_"
	if strings.HasPrefix(name, allocTokenPrefix) {
		a, err := allocToken(name[len(allocTokenPrefix):], options...)
		return a, adjustErr(err, len(allocTokenPrefix))
	}

	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
	}
}

// allocToken handles Clang allocation token names,
// as described at https://clang.llvm.org/docs/AllocToken.html.
// Here name is the name after the __alloc_token_ prefix.
//
// As far as I can tell only a few such names are ever generated,
// so I don't know why they introduced a new mangling scheme,
// but it seems that they did.
func allocToken(name string, options ...Option) (AST, error) {
	// Names look like __alloc_token_[num_]NAME
	// We've skipped the __alloc_token_ already.
	// The num is not included in the demangled name.

	adj := 0
	if len(name) > adj && isDigit(name[adj]) {
		adj++
		for len(name) > adj && isDigit(name[adj]) {
			adj++
		}
		if len(name) <= adj || name[adj] != '_' {
			return nil, ErrNotMangledName
		}
		adj++
	}
	if !strings.HasPrefix(name[adj:], "_Z") {
		return nil, ErrNotMangledName
	}
	adj += 2
	a, err := doDemangle(name[adj:], options...)
	if err == nil {
		a = &Clone{Base: a, Suffix: ".alloc_token"}
	}
	return a, adjustErr(err, adj)
}

// 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 {
		case o == NoParams:
			params = false
			clones = false
		case o == NoClones:
			clones = false
		case o == Verbose:
			verbose = true
		case o == NoTemplateParams || o == NoEnclosingParams || o == LLVMStyle || isMaxLength(o):
			// These are valid options but only affect
			// printing of the AST.
		case o == NoRust:
			// Unimportant here.
		default:
			return nil, fmt.Errorf("unrecognized demangler option %v", o)
		}
	}

	st := &state{str: name, verbose: verbose}
	a := st.encoding(params, notForLocalName)

	// 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

	// The number of entries in templates when we started parsing
	// a lambda, plus 1 so that 0 means not parsing a lambda.
	lambdaTemplateLevel int

	parsingConstraint bool // whether parsing a constraint expression

	// Counts of template parameters without template arguments,
	// for lambdas.
	typeTemplateParamCount     int
	nonTypeTemplateParamCount  int
	templateTemplateParamCount int
}

// 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
}

type forLocalNameType int

const (
	forLocalName forLocalNameType = iota
	notForLocalName
)

// encoding parses:
//
//	encoding ::= <(function) name> <bare-function-type>
//	             <(data) name>
//	             <special-name>
func (st *state) encoding(params bool, local forLocalNameType) AST {
	if len(st.str) < 1 {
		st.fail("expected encoding")
	}

	if st.str[0] == 'G' || st.str[0] == 'T' {
		return st.specialName()
	}

	a, explicitObjectParameter := 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
	}

	mwq, _ := a.(*MethodWithQualifiers)

	var findTemplate func(AST) *Template
	findTemplate = func(check AST) *Template {
		switch check := check.(type) {
		case *Template:
			return check
		case *Qualified:
			if check.LocalName {
				return findTemplate(check.Name)
			} else if _, ok := check.Name.(*Constructor); ok {
				return findTemplate(check.Name)
			}
		case *MethodWithQualifiers:
			return findTemplate(check.Method)
		case *Constructor:
			if check.Base != nil {
				return findTemplate(check.Base)
			}
		case *Constraint:
			return findTemplate(check.Name)
		}
		return nil
	}

	template := findTemplate(a)
	var oldLambdaTemplateLevel int
	if template != nil {
		st.templates = append(st.templates, template)
		oldLambdaTemplateLevel = st.lambdaTemplateLevel
		st.lambdaTemplateLevel = 0
	}

	// Checking for the enable_if attribute here is what the LLVM
	// demangler does.  This is not very general but perhaps it is
	// sufficient.
	const enableIfPrefix = "Ua9enable_ifI"
	var (
		enableIfArgs       []AST
		enableIfConstraint AST
	)
	if strings.HasPrefix(st.str, enableIfPrefix) {
		st.advance(len(enableIfPrefix) - 1)
		enableIfArgs, enableIfConstraint = st.templateArgs()
	}

	ft := st.bareFunctionType(hasReturnType(a), explicitObjectParameter)

	var constraint AST
	if len(st.str) > 0 && st.str[0] == 'Q' {
		constraint = st.constraintExpr()
	}

	if template != nil {
		st.templates = st.templates[:len(st.templates)-1]
		st.lambdaTemplateLevel = oldLambdaTemplateLevel
	}

	ft = simplify(ft)

	// For a local name, discard the return type, so that it
	// doesn't get confused with the top level return type.
	if local == forLocalName {
		if functype, ok := ft.(*FunctionType); ok {
			functype.ForLocalName = true
		}
	}

	// 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
		}
	}

	// Any top-level constraint belongs on the function type.
	var forTemplateArgs bool
	if c, ok := a.(*Constraint); ok && constraint == nil {
		a = c.Name
		constraint = c.Requires
		forTemplateArgs = c.ForTemplateArgs
	}

	r := AST(&Typed{Name: a, Type: ft})

	if len(enableIfArgs) > 0 {
		r = &EnableIf{Type: r, Args: enableIfArgs}
		r = st.maybeAddConstraint(r, enableIfConstraint)
	}

	if constraint != nil {
		r = &Constraint{
			Name:            r,
			Requires:        constraint,
			ForTemplateArgs: forTemplateArgs,
		}
	}

	return r
}

// hasReturnType returns whether the mangled form of a will have a
// return type.
func hasReturnType(a AST) bool {
	switch a := a.(type) {
	case *Qualified:
		if a.LocalName {
			return hasReturnType(a.Name)
		}
		return false
	case *Template:
		return !isCDtorConversion(a.Name)
	case *TypeWithQualifiers:
		return hasReturnType(a.Base)
	case *MethodWithQualifiers:
		return hasReturnType(a.Method)
	case *Constraint:
		return hasReturnType(a.Name)
	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
	}
}

// taggedName parses:
//
//	<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 parses:
//
//	<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>
//
// Besides the name, this returns whether it saw the code indicating
// a C++23 explicit object parameter.
func (st *state) name() (AST, bool) {
	if len(st.str) < 1 {
		st.fail("expected name")
	}

	var module AST
	switch st.str[0] {
	case 'N':
		return st.nestedName()
	case 'Z':
		return st.localName()
	case 'U':
		a, isCast := st.unqualifiedName(nil)
		if isCast {
			st.setTemplate(a, nil)
		}
		return a, false
	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(nil)
			a = &Qualified{Scope: &Name{Name: "std"}, Name: a, LocalName: false}
		} else {
			a = st.substitution(false)
			if mn, ok := a.(*ModuleName); ok {
				module = mn
				break
			}
			subst = true
		}
		var constraint AST
		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)
			}
			var args []AST
			args, constraint = 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)
		}
		a = st.maybeAddConstraint(a, constraint)
		return a, false
	}

	a, isCast := st.unqualifiedName(module)
	var constraint AST
	if len(st.str) > 0 && st.str[0] == 'I' {
		st.subs.add(a)
		var args []AST
		args, constraint = 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)
	}
	a = st.maybeAddConstraint(a, constraint)
	return a, false
}

// nestedName parses:
//
//	<nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
//	              ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
//
// Besides the name, this returns whether it saw the code indicating
// a C++23 explicit object parameter.
func (st *state) nestedName() (AST, bool) {
	st.checkChar('N')

	var q AST
	var r string

	explicitObjectParameter := false
	if len(st.str) > 0 && st.str[0] == 'H' {
		st.advance(1)
		explicitObjectParameter = true
	} else {
		q = st.cvQualifiers()
		r = st.refQualifier()
	}

	a := st.prefix()

	if q != nil || 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, explicitObjectParameter
}

// prefix parses:
//
//	<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

	var module 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
			}
		}
	}

	var cast *Cast
	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' || c == 'F' || c == 'W' || (c == 'D' && len(st.str) > 1 && st.str[1] == 'C') {
			un, isUnCast := st.unqualifiedName(module)
			next = un
			module = nil
			if isUnCast {
				if cast != nil {
					st.fail("cast in scope of cast")
				}
				if m, ok := un.(*ModuleEntity); ok {
					un = m.Name
				}
				for {
					tn, ok := un.(*TaggedName)
					if !ok {
						break
					}
					un = tn.Name
				}
				if f, ok := un.(*Friend); ok {
					un = f.Name
				}
				cast = un.(*Cast)
			}
		} else {
			switch st.str[0] {
			case 'C':
				inheriting := false
				st.advance(1)
				if len(st.str) > 0 && st.str[0] == 'I' {
					inheriting = true
					st.advance(1)
				}
				if len(st.str) < 1 {
					st.fail("expected constructor type")
				}
				if last == nil {
					st.fail("constructor before name is seen")
				}
				switch st.str[0] {
				// 0 is not used.
				case '1', '2', '3', '4', '5':
				default:
					st.fail("unknown constructor type")
				}
				st.advance(1)
				var base AST
				if inheriting {
					base = st.demangleType(false)
				}
				next = &Constructor{
					Name: getLast(last),
					Base: base,
				}
				if len(st.str) > 0 && st.str[0] == 'B' {
					next = st.taggedName(next)
				}
			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")
					}
					switch st.str[1] {
					// 3 is not used.
					case '0', '1', '2', '4', '5':
					default:
						st.fail("unknown destructor type")
					}
					st.advance(2)
					next = &Destructor{Name: getLast(last)}
					if len(st.str) > 0 && st.str[0] == 'B' {
						next = st.taggedName(next)
					}
				}
			case 'S':
				next = st.substitution(true)
				if mn, ok := next.(*ModuleName); ok {
					module = mn
					next = nil
				}
			case 'I':
				if a == nil {
					st.fail("unexpected template arguments")
				}
				args, constraint := st.templateArgs()
				tmpl := &Template{Name: a, Args: args}
				if cast != nil {
					st.setTemplate(cast, tmpl)
					st.clearTemplateArgs(args)
					cast = nil
				}
				a = nil
				next = st.maybeAddConstraint(tmpl, constraint)
			case 'T':
				next = st.templateParam()
			case 'E':
				if a == nil {
					st.fail("expected prefix")
				}
				if cast != nil {
					var toTmpl *Template
					if castTempl, ok := cast.To.(*Template); ok {
						toTmpl = castTempl
					}
					st.setTemplate(cast, toTmpl)
				}
				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
			case 'J':
				// It appears that in some cases clang
				// can emit a J for a template arg
				// without the expected I.  I don't
				// know when this happens, but I've
				// seen it in some large C++ programs.
				if a == nil {
					st.fail("unexpected template arguments")
				}
				var args []AST
				for len(st.str) == 0 || st.str[0] != 'E' {
					arg := st.templateArg(nil)
					args = append(args, arg)
				}
				st.advance(1)
				tmpl := &Template{Name: a, Args: args}
				if cast != nil {
					st.setTemplate(cast, tmpl)
					st.clearTemplateArgs(args)
					cast = nil
				}
				a = nil
				next = tmpl
			default:
				st.fail("unrecognized letter in prefix")
			}
		}

		if next == nil {
			continue
		}

		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)
		}
	}
}

// unqualifiedName parses:
//
//	<unqualified-name> ::= <operator-name>
//	                   ::= <ctor-dtor-name>
//	                   ::= <source-name>
//	                   ::= <local-source-name>
//
//	 <local-source-name>	::= L <source-name> <discriminator>
func (st *state) unqualifiedName(module AST) (r AST, isCast bool) {
	module = st.moduleName(module)

	if len(st.str) < 1 {
		st.fail("expected unqualified name")
	}

	friend := false
	if len(st.str) > 0 && st.str[0] == 'F' {
		st.advance(1)
		friend = true
		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 if c == 'D' && len(st.str) > 1 && st.str[1] == 'C' {
		var bindings []AST
		st.advance(2)
		for {
			binding := st.sourceName()
			bindings = append(bindings, binding)
			if len(st.str) > 0 && st.str[0] == 'E' {
				st.advance(1)
				break
			}
		}
		a = &StructuredBindings{Bindings: bindings}
	} else {
		switch c {
		case 'C', 'D':
			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 'b':
				st.advance(2)
				st.compactNumber()
				a = &Name{Name: "'block-literal'"}
			case 'e':
				a = st.unnamedEnum()
			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 module != nil {
		a = &ModuleEntity{Module: module, Name: a}
	}

	if len(st.str) > 0 && st.str[0] == 'B' {
		a = st.taggedName(a)
	}

	if friend {
		a = &Friend{Name: a}
	}

	return a, isCast
}

// sourceName parses:
//
//	<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
}

// moduleName parses:
//
//	<module-name> ::= <module-subname>
//	 	      ::= <module-name> <module-subname>
//		      ::= <substitution>  # passed in by caller
//	<module-subname> ::= W <source-name>
//			 ::= W P <source-name>
//
// The module name is optional. If it is not present, this returns the parent.
func (st *state) moduleName(parent AST) AST {
	ret := parent
	for len(st.str) > 0 && st.str[0] == 'W' {
		st.advance(1)
		isPartition := false
		if len(st.str) > 0 && st.str[0] == 'P' {
			st.advance(1)
			isPartition = true
		}
		name := st.sourceName()
		ret = &ModuleName{
			Parent:      ret,
			Name:        name,
			IsPartition: isPartition,
		}
		st.subs.add(ret)
	}
	return ret
}

// number parses:
//
//	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
}

// seqID parses:
//
//	<seq-id> ::= <0-9A-Z>+
//
// We expect this to be followed by an underscore.
func (st *state) seqID(eofOK bool) int {
	if len(st.str) > 0 && st.str[0] == '_' {
		st.advance(1)
		return 0
	}
	id := 0
	for {
		if len(st.str) == 0 {
			if eofOK {
				return id + 1
			}
			st.fail("missing end to sequence ID")
		}
		// Don't overflow a 32-bit int.
		if id >= 0x80000000/36-36 {
			st.fail("sequence ID overflow")
		}
		c := st.str[0]
		if c == '_' {
			st.advance(1)
			return id + 1
		}
		if isDigit(c) {
			id = id*36 + int(c-'0')
		} else if isUpper(c) {
			id = id*36 + int(c-'A') + 10
		} else {
			st.fail("invalid character in sequence ID")
		}
		st.advance(1)
	}
}

// An operator is the demangled name, and the number of arguments it
// takes in an expression.
type operator struct {
	name string
	args int
	prec precedence
}

// The operators map maps the mangled operator names to information
// about them.
var operators = map[string]operator{
	"aN": {"&=", 2, precAssign},
	"aS": {"=", 2, precAssign},
	"aa": {"&&", 2, precLogicalAnd},
	"ad": {"&", 1, precUnary},
	"an": {"&", 2, precAnd},
	"at": {"alignof ", 1, precUnary},
	"aw": {"co_await ", 1, precPrimary},
	"az": {"alignof ", 1, precUnary},
	"cc": {"const_cast", 2, precPostfix},
	"cl": {"()", 2, precPostfix},
	// cp is not in the ABI but is used by clang "when the call
	// would use ADL except for being parenthesized."
	// The trailing space indicates this to the printer.
	"cp": {"() ", 2, precPostfix},
	"cm": {",", 2, precComma},
	"co": {"~", 1, precUnary},
	"dV": {"/=", 2, precAssign},
	"dX": {"[...]=", 3, precAssign},
	"da": {"delete[] ", 1, precUnary},
	"dc": {"dynamic_cast", 2, precPostfix},
	"de": {"*", 1, precUnary},
	"di": {"=", 2, precAssign},
	"dl": {"delete ", 1, precUnary},
	"ds": {".*", 2, precPtrMem},
	"dt": {".", 2, precPostfix},
	"dv": {"/", 2, precAssign},
	"dx": {"]=", 2, precAssign},
	"eO": {"^=", 2, precAssign},
	"eo": {"^", 2, precXor},
	"eq": {"==", 2, precEqual},
	"fl": {"...", 2, precPrimary},
	"fr": {"...", 2, precPrimary},
	"fL": {"...", 3, precPrimary},
	"fR": {"...", 3, precPrimary},
	"ge": {">=", 2, precRel},
	"gs": {"::", 1, precUnary},
	"gt": {">", 2, precRel},
	"ix": {"[]", 2, precPostfix},
	"lS": {"<<=", 2, precAssign},
	"le": {"<=", 2, precRel},
	"li": {`operator"" `, 1, precUnary},
	"ls": {"<<", 2, precShift},
	"lt": {"<", 2, precRel},
	"mI": {"-=", 2, precAssign},
	"mL": {"*=", 2, precAssign},
	"mi": {"-", 2, precAdd},
	"ml": {"*", 2, precMul},
	"mm": {"--", 1, precPostfix},
	"na": {"new[]", 3, precUnary},
	"ne": {"!=", 2, precEqual},
	"ng": {"-", 1, precUnary},
	"nt": {"!", 1, precUnary},
	"nw": {"new", 3, precUnary},
	"nx": {"noexcept", 1, precUnary},
	"oR": {"|=", 2, precAssign},
	"oo": {"||", 2, precLogicalOr},
	"or": {"|", 2, precOr},
	"pL": {"+=", 2, precAssign},
	"pl": {"+", 2, precAdd},
	"pm": {"->*", 2, precPtrMem},
	"pp": {"++", 1, precPostfix},
	"ps": {"+", 1, precUnary},
	"pt": {"->", 2, precPostfix},
	"qu": {"?", 3, precCond},
	"rM": {"%=", 2, precAssign},
	"rS": {">>=", 2, precAssign},
	"rc": {"reinterpret_cast", 2, precPostfix},
	"rm": {"%", 2, precMul},
	"rs": {">>", 2, precShift},
	"sP": {"sizeof...", 1, precUnary},
	"sZ": {"sizeof...", 1, precUnary},
	"sc": {"static_cast", 2, precPostfix},
	"ss": {"<=>", 2, precSpaceship},
	"st": {"sizeof ", 1, precUnary},
	"sz": {"sizeof ", 1, precUnary},
	"te": {"typeid ", 1, precPostfix},
	"ti": {"typeid ", 1, precPostfix},
	"tr": {"throw", 0, precPrimary},
	"tw": {"throw ", 1, precUnary},
}

// operatorName parses:
//
//	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, precedence: op.prec}, op.args
	} else {
		st.failEarlier("unrecognized operator code", 2)
		panic("not reached")
	}
}

// localName parses:
//
//	<local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
//	             ::= Z <(function) encoding> E s [<discriminator>]
//	             ::= Z <(function) encoding> E d [<parameter> number>] _ <entity name>
//
// Besides the name, this returns whether it saw the code indicating
// a C++23 explicit object parameter.
func (st *state) localName() (AST, bool) {
	st.checkChar('Z')
	fn := st.encoding(true, forLocalName)
	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}, false
	} else {
		num := -1
		if len(st.str) > 0 && st.str[0] == 'd' {
			// Default argument scope.
			st.advance(1)
			num = st.compactNumber()
		}
		n, explicitObjectParameter := st.name()
		n = st.discriminator(n)
		if num >= 0 {
			n = &DefaultArg{Num: num, Arg: n}
		}
		return &Qualified{Scope: fn, Name: n, LocalName: true}, explicitObjectParameter
	}
}

// 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}}
}

// specialName parses:
//
//	<special-name> ::= TV <type>
//	               ::= TT <type>
//	               ::= TI <type>
//	               ::= TS <type>
//	               ::= TA <template-arg>
//	               ::= GV <(object) name>
//	               ::= T <call-offset> <(base) encoding>
//	               ::= Tc <call-offset> <call-offset> <(base) encoding>
//	g++ extensions:
//	               ::= TC <type> <(offset) number> _ <(base) type>
//	               ::= TF <type>
//	               ::= TJ <type>
//	               ::= GR <name>
//	               ::= GA <encoding>
//	               ::= Gr <resource name>
//	               ::= GTt <encoding>
//	               ::= GTn <encoding>
//	               ::= GI <module name>
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 'A':
			t := st.templateArg(nil)
			return &Special{Prefix: "template parameter object for ", Val: t}
		case 'h':
			st.callOffset('h')
			v := st.encoding(true, notForLocalName)
			return &Special{Prefix: "non-virtual thunk to ", Val: v}
		case 'v':
			st.callOffset('v')
			v := st.encoding(true, notForLocalName)
			return &Special{Prefix: "virtual thunk to ", Val: v}
		case 'c':
			st.callOffset(0)
			st.callOffset(0)
			v := st.encoding(true, notForLocalName)
			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()
			st.seqID(true)
			return &Special{Prefix: "reference temporary for ", Val: n}
		case 'A':
			v := st.encoding(true, notForLocalName)
			return &Special{Prefix: "hidden alias for ", Val: v}
		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, notForLocalName)
			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()
		case 'I':
			module := st.moduleName(nil)
			if module == nil {
				st.fail("expected module after GI")
			}
			return &Special{Prefix: "initializer for module ", Val: module}
		default:
			st.fail("unrecognized special G name code")
			panic("not reached")
		}
	}
}

// callOffset parses:
//
//	<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': "...",
}

// demangleType parses:
//
//	<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 q != nil {
		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 q != nil {
			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()
		if len(st.str) > 0 && st.str[0] == 'I' {
			st.advance(1)
			base := st.demangleType(false)
			if len(st.str) == 0 || st.str[0] != 'E' {
				st.fail("expected E after transformed type")
			}
			st.advance(1)
			ret = &TransformedType{Name: ret.(*Name).Name, Base: base}
		}
	case 'F':
		ret = st.functionType()
	case 'N', 'W', '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':
		if len(st.str) > 1 && (st.str[1] == 's' || st.str[1] == 'u' || st.str[1] == 'e') {
			c = st.str[1]
			st.advance(2)
			ret, _ = st.name()
			var kind string
			switch c {
			case 's':
				kind = "struct"
			case 'u':
				kind = "union"
			case 'e':
				kind = "enum"
			}
			ret = &ElaboratedType{Kind: kind, Type: ret}
			break
		}

		ret = st.templateParam()
		if len(st.str) > 0 && st.str[0] == 'I' {
			// See the function comment to explain this.
			if !isCast {
				st.subs.add(ret)
				ret = st.template(ret)
			} 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 _, ok := ret.(*ModuleName); ok {
				var isCast bool
				ret, isCast = st.unqualifiedName(ret)
				if isCast {
					st.setTemplate(ret, nil)
				}
				st.subs.add(ret)
			}
			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 {
					ret = st.template(ret)
				} 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 'e':
			ret = st.unnamedEnum()
			addSubst = false
		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' {
				n = st.template(n)
			}
			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)

		fixedPrefix := func(c byte) (string, bool) {
			switch c {
			case 's':
				return "short ", true
			case 't':
				return "unsigned short ", true
			case 'i':
				return "", true
			case 'j':
				return "unsigned ", true
			case 'l':
				return "long ", true
			case 'm':
				return "unsigned long ", true
			default:
				return "", false
			}
		}

		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 'c':
			ret = &Name{Name: "decltype(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 'u':
			ret = &BuiltinType{Name: "char8_t"}
		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
			bits := 0
			if len(st.str) > 0 && isDigit(st.str[0]) {
				accum = true
				bits = st.number()
			}
			if len(st.str) > 0 && st.str[0] == '_' {
				if bits == 0 {
					st.fail("expected non-zero number of bits")
				}
				st.advance(1)
				ret = &BinaryFP{Bits: bits, Suffix: ""}
			} else if len(st.str) > 0 && st.str[0] == 'x' {
				if bits == 0 {
					st.fail("expected non-zero number of bits")
				}
				st.advance(1)
				ret = &BinaryFP{Bits: bits, Suffix: "x"}
			} else if len(st.str) > 0 && st.str[0] == 'b' {
				if bits != 16 {
					st.fail("expected bits to be 16 for std::bfloat16_t")
				}
				st.advance(1)
				ret = &BuiltinType{Name: "std::bfloat16_t"}
			} else {
				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

		case 'B', 'U':
			signed := c2 == 'B'
			var size AST
			if len(st.str) > 0 && isDigit(st.str[0]) {
				bits := st.number()
				size = &Name{Name: fmt.Sprintf("%d", bits)}
			} else {
				size = st.expression()
			}
			if len(st.str) == 0 || st.str[0] != '_' {
				st.fail("expected _ after _BitInt size")
			}
			st.advance(1)
			ret = &BitIntType{Size: size, Signed: signed}
			addSubst = true

		case 'k':
			constraint, _ := st.name()
			ret = &SuffixType{
				Base:   constraint,
				Suffix: "auto",
			}

		case 'K':
			constraint, _ := st.name()
			ret = &SuffixType{
				Base:   constraint,
				Suffix: "decltype(auto)",
			}

		case 'A', 'R':
			if len(st.str) == 0 {
				st.fail("missing D{A,R} code in type")
			}
			prefix, ok := fixedPrefix(st.str[0])
			if !ok {
				st.fail("unrecognized D{A,R} code in type")
			}
			st.advance(1)

			switch c2 {
			case 'A':
				ret = &BuiltinType{Name: prefix + "_Accum"}
			case 'R':
				ret = &BuiltinType{Name: prefix + "_Fract"}
			default:
				panic("internal error")
			}

		case 'S':
			if len(st.str) < 3 {
				st.fail("missing DS code in type")
			}
			if st.str[0] != 'D' {
				st.fail("unrecognized DS code in type")
			}

			var suffix string
			switch st.str[1] {
			case 'A':
				suffix = "_Accum"
			case 'R':
				suffix = "_Fract"
			default:
				st.fail("unrecognized DSD code in type")
			}

			prefix, ok := fixedPrefix(st.str[2])
			if !ok {
				st.fail("unrecognized DSD{A,R} code in type")
			}

			st.advance(3)

			ret = &BuiltinType{Name: "_Sat " + prefix + suffix}

		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 q != nil {
		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
		constraint AST
	)
	failed := false
	func() {
		defer func() {
			if r := recover(); r != nil {
				if _, ok := r.(demangleErr); ok {
					failed = true
				} else {
					panic(r)
				}
			}
		}()

		args, constraint = st.templateArgs()
	}()

	if !failed && len(st.str) > 0 && st.str[0] == 'I' {
		if addSubst {
			st.subs.add(tp)
		}
		ret := &Template{Name: tp, Args: args}
		return st.maybeAddConstraint(ret, constraint)
	}
	// 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 qualifier lists into one.
func mergeQualifiers(q1AST, q2AST AST) AST {
	if q1AST == nil {
		return q2AST
	}
	if q2AST == nil {
		return q1AST
	}
	q1 := q1AST.(*Qualifiers)
	m := make(map[string]bool)
	for _, qualAST := range q1.Qualifiers {
		qual := qualAST.(*Qualifier)
		if len(qual.Exprs) == 0 {
			m[qual.Name] = true
		}
	}
	rq := q1.Qualifiers
	for _, qualAST := range q2AST.(*Qualifiers).Qualifiers {
		qual := qualAST.(*Qualifier)
		if len(qual.Exprs) > 0 {
			rq = append(rq, qualAST)
		} else if !m[qual.Name] {
			rq = append(rq, qualAST)
			m[qual.Name] = true
		}
	}
	q1.Qualifiers = rq
	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",
}

// cvQualifiers parses:
//
//	<CV-qualifiers> ::= [r] [V] [K]
func (st *state) cvQualifiers() AST {
	var q []AST
qualLoop:
	for len(st.str) > 0 {
		if qv, ok := qualifiers[st.str[0]]; ok {
			qual := &Qualifier{Name: qv}
			q = append([]AST{qual}, q...)
			st.advance(1)
		} else if len(st.str) > 1 && st.str[0] == 'D' {
			var qual AST
			switch st.str[1] {
			case 'x':
				qual = &Qualifier{Name: "transaction_safe"}
				st.advance(2)
			case 'o':
				qual = &Qualifier{Name: "noexcept"}
				st.advance(2)
			case 'O':
				st.advance(2)
				expr := st.expression()
				if len(st.str) == 0 || st.str[0] != 'E' {
					st.fail("expected E after computed noexcept expression")
				}
				st.advance(1)
				qual = &Qualifier{Name: "noexcept", Exprs: []AST{expr}}
			case 'w':
				st.advance(2)
				parmlist := st.parmlist(false)
				if len(st.str) == 0 || st.str[0] != 'E' {
					st.fail("expected E after throw parameter list")
				}
				st.advance(1)
				qual = &Qualifier{Name: "throw", Exprs: parmlist}
			default:
				break qualLoop
			}
			q = append([]AST{qual}, q...)
		} else {
			break
		}
	}
	if len(q) == 0 {
		return nil
	}
	return &Qualifiers{Qualifiers: q}
}

// refQualifier parses:
//
//	<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 ""
}

// parmlist parses:
//
//	<type>+
func (st *state) parmlist(explicitObjectParameter bool) []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
		}
		if st.str[0] == 'Q' {
			// This is a requires clause.
			break
		}
		ptype := st.demangleType(false)

		if len(ret) == 0 && explicitObjectParameter {
			ptype = &ExplicitObjectParameter{Base: ptype}
		}

		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
}

// functionType parses:
//
//	<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, false)
	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
}

// bareFunctionType parses:
//
//	<bare-function-type> ::= [J]<type>+
func (st *state) bareFunctionType(hasReturnType, explicitObjectParameter 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(explicitObjectParameter)
	return &FunctionType{
		Return:       returnType,
		Args:         types,
		ForLocalName: false, // may be set later in encoding
	}
}

// arrayType parses:
//
//	<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
}

// vectorType parses:
//
//	<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}
}

// pointerToMemberType parses:
//
//	<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}
}

// compactNumber parses:
//
//	<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
}

// templateParam parses:
//
//	<template-param> ::= T_
//	                 ::= T <(parameter-2 non-negative) number> _
//	                 ::= TL <level-1> __
//	                 ::= TL <level-1> _ <parameter-2 non-negative number> _
//
// When a template parameter is a substitution candidate, any
// reference to that substitution refers to the template parameter
// 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 {
	off := st.off
	str := st.str
	st.checkChar('T')

	level := 0
	if len(st.str) > 0 && st.str[0] == 'L' {
		st.advance(1)
		level = st.compactNumber()
	}

	n := st.compactNumber()

	// We don't try to substitute template parameters in a
	// constraint expression.
	if st.parsingConstraint {
		return &Name{Name: str[:st.off-1-off]}
	}

	if level >= len(st.templates) {
		if st.lambdaTemplateLevel > 0 && level == st.lambdaTemplateLevel-1 {
			// Lambda auto params are mangled as template params.
			// See https://gcc.gnu.org/PR78252.
			return &LambdaAuto{Index: n}
		}
		st.failEarlier(fmt.Sprintf("template parameter is not in scope of template (level %d >= %d)", level, len(st.templates)), st.off-off)
	}

	template := st.templates[level]

	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) {
		if st.lambdaTemplateLevel > 0 && level == st.lambdaTemplateLevel-1 {
			// Lambda auto params are mangled as template params.
			// See https://gcc.gnu.org/PR78252.
			return &LambdaAuto{Index: n}
		}
		st.failEarlier(fmt.Sprintf("template index out of range (%d >= %d)", n, len(template.Args)), st.off-off)
	}

	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) {
	seen := make(map[AST]bool)
	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
		case *Closure:
			// There are no template params in closure types.
			// https://gcc.gnu.org/PR78252.
			if tmpl == nil {
				a.Traverse(func(a AST) bool {
					if tmplParam, ok := a.(*TemplateParam); ok && tmplParam.Template == nil {
						st.fail("cast template parameter not in scope of template")
					}
					if seen[a] {
						return false
					}
					seen[a] = true
					return true
				})
			}
			return false
		default:
			if seen[a] {
				return false
			}
			seen[a] = true
			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)
	}
}

// templateArgs parses:
//
//	<template-args> ::= I <template-arg>+ E
//
// This returns the template arguments and an optional constraint.
func (st *state) templateArgs() ([]AST, AST) {
	if len(st.str) == 0 || (st.str[0] != 'I' && st.str[0] != 'J') {
		panic("internal error")
	}
	st.advance(1)

	var (
		ret        []AST
		constraint AST
	)
	for len(st.str) == 0 || st.str[0] != 'E' {
		arg := st.templateArg(ret)
		ret = append(ret, arg)

		if len(st.str) > 0 && st.str[0] == 'Q' {
			constraint = st.constraintExpr()
			if len(st.str) == 0 || st.str[0] != 'E' {
				st.fail("expected end of template arguments after constraint")
			}
		}
	}
	st.advance(1)
	return ret, constraint
}

// templateArg parses:
//
//	<template-arg> ::= <type>
//	               ::= X <expression> E
//	               ::= <expr-primary>
//	               ::= J <template-arg>* E
//	               ::= LZ <encoding> E
//	               ::= <template-param-decl> <template-arg>
func (st *state) templateArg(prev []AST) 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, constraint := st.templateArgs()
		ret := &ArgumentPack{Args: args}
		return st.maybeAddConstraint(ret, constraint)

	case 'T':
		var arg byte
		if len(st.str) > 1 {
			arg = st.str[1]
		}
		switch arg {
		case 'y', 'n', 't', 'p', 'k':
			off := st.off

			// Apparently template references in the
			// template parameter refer to previous
			// arguments in the same template.
			template := &Template{Args: prev}
			st.templates = append(st.templates, template)

			param, _ := st.templateParamDecl()

			st.templates = st.templates[:len(st.templates)-1]

			if param == nil {
				st.failEarlier("expected template parameter as template argument", st.off-off)
			}
			arg := st.templateArg(nil)
			return &TemplateParamQualifiedArg{Param: param, Arg: arg}
		}
		return st.demangleType(false)

	default:
		return st.demangleType(false)
	}
}

// maybeAddConstraint adds a constraint to an AST, if constraint is not nil.
// This is only called with a constraint found at the end of
// template arguments.
func (st *state) maybeAddConstraint(a, constraint AST) AST {
	if constraint == nil {
		return a
	}
	return &Constraint{
		Name:            a,
		Requires:        constraint,
		ForTemplateArgs: true,
	}
}

// template parses template arguments into a Template with a given name.
func (st *state) template(name AST) AST {
	args, constraint := st.templateArgs()
	ret := &Template{Name: name, Args: args}
	return st.maybeAddConstraint(ret, constraint)
}

// 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 parses:
//
//	<expression> ::= <(unary) operator-name> <expression>
//	             ::= <(binary) operator-name> <expression> <expression>
//	             ::= <(trinary) operator-name> <expression> <expression> <expression>
//	             ::= pp_ <expression>
//	             ::= mm_ <expression>
//	             ::= cl <expression>+ E
//	             ::= cl <expression>+ E
//	             ::= cv <type> <expression>
//	             ::= cv <type> _ <expression>* E
//	             ::= tl <type> <braced-expression>* E
//	             ::= il <braced-expression>* E
//	             ::= [gs] nw <expression>* _ <type> E
//	             ::= [gs] nw <expression>* _ <type> <initializer>
//	             ::= [gs] na <expression>* _ <type> E
//	             ::= [gs] na <expression>* _ <type> <initializer>
//	             ::= [gs] dl <expression>
//	             ::= [gs] da <expression>
//	      
Download .txt
gitextract_d03jdduc/

├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── ast.go
├── ast_test.go
├── c++filt.go
├── cases_test.go
├── demangle.go
├── demangle_test.go
├── expected_test.go
├── fuzz_test.go
├── go.mod
├── rust.go
├── rust_expected_test.go
└── testdata/
    ├── DemangleTestCases.inc
    ├── demangle-expected
    ├── rust-demangle-expected
    └── rust.test
Download .txt
SYMBOL INDEX (685 symbols across 10 files)

FILE: ast.go
  type AST (line 16) | type AST interface
  function ASTToString (line 40) | func ASTToString(a AST, options ...Option) string {
  type printState (line 74) | type printState struct
    method writeByte (line 111) | func (ps *printState) writeByte(b byte) {
    method writeString (line 117) | func (ps *printState) writeString(s string) {
    method print (line 125) | func (ps *printState) print(a AST) {
    method printList (line 155) | func (ps *printState) printList(args []AST, skip func(AST) bool) {
    method startScope (line 189) | func (ps *printState) startScope(b byte) {
    method endScope (line 195) | func (ps *printState) endScope(b byte) {
    method printInner (line 5402) | func (ps *printState) printInner(prefixOnly bool) []AST {
    method printOneInner (line 5422) | func (ps *printState) printOneInner(save *[]AST) {
    method isEmpty (line 5445) | func (ps *printState) isEmpty(a AST) bool {
  type precedence (line 202) | type precedence
  constant precPrimary (line 206) | precPrimary precedence = iota
  constant precPostfix (line 207) | precPostfix
  constant precUnary (line 208) | precUnary
  constant precCast (line 209) | precCast
  constant precPtrMem (line 210) | precPtrMem
  constant precMul (line 211) | precMul
  constant precAdd (line 212) | precAdd
  constant precShift (line 213) | precShift
  constant precSpaceship (line 214) | precSpaceship
  constant precRel (line 215) | precRel
  constant precEqual (line 216) | precEqual
  constant precAnd (line 217) | precAnd
  constant precXor (line 218) | precXor
  constant precOr (line 219) | precOr
  constant precLogicalAnd (line 220) | precLogicalAnd
  constant precLogicalOr (line 221) | precLogicalOr
  constant precCond (line 222) | precCond
  constant precAssign (line 223) | precAssign
  constant precComma (line 224) | precComma
  constant precDefault (line 225) | precDefault
  type hasPrec (line 230) | type hasPrec interface
  type Name (line 235) | type Name struct
    method print (line 239) | func (n *Name) print(ps *printState) {
    method Traverse (line 243) | func (n *Name) Traverse(fn func(AST) bool) {
    method Copy (line 247) | func (n *Name) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 254) | func (n *Name) GoString() string {
    method goString (line 258) | func (n *Name) goString(indent int, field string) string {
    method prec (line 262) | func (n *Name) prec() precedence {
  type Typed (line 267) | type Typed struct
    method print (line 272) | func (t *Typed) print(ps *printState) {
    method printInner (line 288) | func (t *Typed) printInner(ps *printState) {
    method Traverse (line 292) | func (t *Typed) Traverse(fn func(AST) bool) {
    method Copy (line 299) | func (t *Typed) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 321) | func (t *Typed) GoString() string {
    method goString (line 325) | func (t *Typed) goString(indent int, field string) string {
  type Qualified (line 332) | type Qualified struct
    method print (line 344) | func (q *Qualified) print(ps *printState) {
    method Traverse (line 350) | func (q *Qualified) Traverse(fn func(AST) bool) {
    method Copy (line 357) | func (q *Qualified) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 379) | func (q *Qualified) GoString() string {
    method goString (line 383) | func (q *Qualified) goString(indent int, field string) string {
    method prec (line 393) | func (q *Qualified) prec() precedence {
  type Template (line 398) | type Template struct
    method print (line 403) | func (t *Template) print(ps *printState) {
    method Traverse (line 435) | func (t *Template) Traverse(fn func(AST) bool) {
    method Copy (line 444) | func (t *Template) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 473) | func (t *Template) GoString() string {
    method goString (line 477) | func (t *Template) goString(indent int, field string) string {
  type TemplateParam (line 496) | type TemplateParam struct
    method print (line 501) | func (tp *TemplateParam) print(ps *printState) {
    method Traverse (line 511) | func (tp *TemplateParam) Traverse(fn func(AST) bool) {
    method Copy (line 516) | func (tp *TemplateParam) Copy(fn func(AST) AST, skip func(AST) bool) A...
    method GoString (line 523) | func (tp *TemplateParam) GoString() string {
    method goString (line 527) | func (tp *TemplateParam) goString(indent int, field string) string {
  type LambdaAuto (line 532) | type LambdaAuto struct
    method print (line 536) | func (la *LambdaAuto) print(ps *printState) {
    method Traverse (line 546) | func (la *LambdaAuto) Traverse(fn func(AST) bool) {
    method Copy (line 550) | func (la *LambdaAuto) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 557) | func (la *LambdaAuto) GoString() string {
    method goString (line 561) | func (la *LambdaAuto) goString(indent int, field string) string {
  type TemplateParamQualifiedArg (line 568) | type TemplateParamQualifiedArg struct
    method print (line 573) | func (tpqa *TemplateParamQualifiedArg) print(ps *printState) {
    method Traverse (line 581) | func (tpqa *TemplateParamQualifiedArg) Traverse(fn func(AST) bool) {
    method Copy (line 588) | func (tpqa *TemplateParamQualifiedArg) Copy(fn func(AST) AST, skip fun...
    method GoString (line 610) | func (tpqa *TemplateParamQualifiedArg) GoString() string {
    method goString (line 614) | func (tpqa *TemplateParamQualifiedArg) goString(indent int, field stri...
  type Qualifiers (line 621) | type Qualifiers struct
    method print (line 625) | func (qs *Qualifiers) print(ps *printState) {
    method Traverse (line 636) | func (qs *Qualifiers) Traverse(fn func(AST) bool) {
    method Copy (line 644) | func (qs *Qualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 669) | func (qs *Qualifiers) GoString() string {
    method goString (line 673) | func (qs *Qualifiers) goString(indent int, field string) string {
  type Qualifier (line 683) | type Qualifier struct
    method print (line 688) | func (q *Qualifier) print(ps *printState) {
    method Traverse (line 707) | func (q *Qualifier) Traverse(fn func(AST) bool) {
    method Copy (line 715) | func (q *Qualifier) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 740) | func (q *Qualifier) GoString() string {
    method goString (line 744) | func (q *Qualifier) goString(indent int, field string) string {
  type TypeWithQualifiers (line 756) | type TypeWithQualifiers struct
    method print (line 761) | func (twq *TypeWithQualifiers) print(ps *printState) {
    method printInner (line 779) | func (twq *TypeWithQualifiers) printInner(ps *printState) {
    method Traverse (line 784) | func (twq *TypeWithQualifiers) Traverse(fn func(AST) bool) {
    method Copy (line 790) | func (twq *TypeWithQualifiers) Copy(fn func(AST) AST, skip func(AST) b...
    method GoString (line 812) | func (twq *TypeWithQualifiers) GoString() string {
    method goString (line 816) | func (twq *TypeWithQualifiers) goString(indent int, field string) stri...
  type MethodWithQualifiers (line 823) | type MethodWithQualifiers struct
    method print (line 829) | func (mwq *MethodWithQualifiers) print(ps *printState) {
    method printInner (line 846) | func (mwq *MethodWithQualifiers) printInner(ps *printState) {
    method Traverse (line 857) | func (mwq *MethodWithQualifiers) Traverse(fn func(AST) bool) {
    method Copy (line 863) | func (mwq *MethodWithQualifiers) Copy(fn func(AST) AST, skip func(AST)...
    method GoString (line 888) | func (mwq *MethodWithQualifiers) GoString() string {
    method goString (line 892) | func (mwq *MethodWithQualifiers) goString(indent int, field string) st...
  type BuiltinType (line 908) | type BuiltinType struct
    method print (line 912) | func (bt *BuiltinType) print(ps *printState) {
    method Traverse (line 920) | func (bt *BuiltinType) Traverse(fn func(AST) bool) {
    method Copy (line 924) | func (bt *BuiltinType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 931) | func (bt *BuiltinType) GoString() string {
    method goString (line 935) | func (bt *BuiltinType) goString(indent int, field string) string {
    method prec (line 939) | func (bt *BuiltinType) prec() precedence {
  function printBase (line 945) | func printBase(ps *printState, qual, base AST) {
  type PointerType (line 955) | type PointerType struct
    method print (line 959) | func (pt *PointerType) print(ps *printState) {
    method printInner (line 963) | func (pt *PointerType) printInner(ps *printState) {
    method Traverse (line 967) | func (pt *PointerType) Traverse(fn func(AST) bool) {
    method Copy (line 973) | func (pt *PointerType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 988) | func (pt *PointerType) GoString() string {
    method goString (line 992) | func (pt *PointerType) goString(indent int, field string) string {
  type ReferenceType (line 998) | type ReferenceType struct
    method print (line 1002) | func (rt *ReferenceType) print(ps *printState) {
    method printInner (line 1006) | func (rt *ReferenceType) printInner(ps *printState) {
    method Traverse (line 1010) | func (rt *ReferenceType) Traverse(fn func(AST) bool) {
    method Copy (line 1016) | func (rt *ReferenceType) Copy(fn func(AST) AST, skip func(AST) bool) A...
    method GoString (line 1031) | func (rt *ReferenceType) GoString() string {
    method goString (line 1035) | func (rt *ReferenceType) goString(indent int, field string) string {
  type RvalueReferenceType (line 1041) | type RvalueReferenceType struct
    method print (line 1045) | func (rt *RvalueReferenceType) print(ps *printState) {
    method printInner (line 1049) | func (rt *RvalueReferenceType) printInner(ps *printState) {
    method Traverse (line 1053) | func (rt *RvalueReferenceType) Traverse(fn func(AST) bool) {
    method Copy (line 1059) | func (rt *RvalueReferenceType) Copy(fn func(AST) AST, skip func(AST) b...
    method GoString (line 1074) | func (rt *RvalueReferenceType) GoString() string {
    method goString (line 1078) | func (rt *RvalueReferenceType) goString(indent int, field string) stri...
  type ComplexType (line 1084) | type ComplexType struct
    method print (line 1088) | func (ct *ComplexType) print(ps *printState) {
    method printInner (line 1092) | func (ct *ComplexType) printInner(ps *printState) {
    method Traverse (line 1096) | func (ct *ComplexType) Traverse(fn func(AST) bool) {
    method Copy (line 1102) | func (ct *ComplexType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 1117) | func (ct *ComplexType) GoString() string {
    method goString (line 1121) | func (ct *ComplexType) goString(indent int, field string) string {
  type ImaginaryType (line 1127) | type ImaginaryType struct
    method print (line 1131) | func (it *ImaginaryType) print(ps *printState) {
    method printInner (line 1135) | func (it *ImaginaryType) printInner(ps *printState) {
    method Traverse (line 1139) | func (it *ImaginaryType) Traverse(fn func(AST) bool) {
    method Copy (line 1145) | func (it *ImaginaryType) Copy(fn func(AST) AST, skip func(AST) bool) A...
    method GoString (line 1160) | func (it *ImaginaryType) GoString() string {
    method goString (line 1164) | func (it *ImaginaryType) goString(indent int, field string) string {
  type SuffixType (line 1170) | type SuffixType struct
    method print (line 1175) | func (st *SuffixType) print(ps *printState) {
    method printInner (line 1179) | func (st *SuffixType) printInner(ps *printState) {
    method Traverse (line 1184) | func (st *SuffixType) Traverse(fn func(AST) bool) {
    method Copy (line 1190) | func (st *SuffixType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 1205) | func (st *SuffixType) GoString() string {
    method goString (line 1209) | func (st *SuffixType) goString(indent int, field string) string {
  type TransformedType (line 1215) | type TransformedType struct
    method print (line 1220) | func (tt *TransformedType) print(ps *printState) {
    method Traverse (line 1227) | func (tt *TransformedType) Traverse(fn func(AST) bool) {
    method Copy (line 1233) | func (tt *TransformedType) Copy(fn func(AST) AST, skip func(AST) bool)...
    method GoString (line 1248) | func (tt *TransformedType) GoString() string {
    method goString (line 1252) | func (tt *TransformedType) goString(indent int, field string) string {
  type VendorQualifier (line 1258) | type VendorQualifier struct
    method print (line 1263) | func (vq *VendorQualifier) print(ps *printState) {
    method printInner (line 1276) | func (vq *VendorQualifier) printInner(ps *printState) {
    method Traverse (line 1281) | func (vq *VendorQualifier) Traverse(fn func(AST) bool) {
    method Copy (line 1288) | func (vq *VendorQualifier) Copy(fn func(AST) AST, skip func(AST) bool)...
    method GoString (line 1310) | func (vq *VendorQualifier) GoString() string {
    method goString (line 1314) | func (vq *VendorQualifier) goString(indent int, field string) string {
  type ArrayType (line 1321) | type ArrayType struct
    method print (line 1326) | func (at *ArrayType) print(ps *printState) {
    method printInner (line 1337) | func (at *ArrayType) printInner(ps *printState) {
    method printDimension (line 1342) | func (at *ArrayType) printDimension(ps *printState) {
    method Traverse (line 1371) | func (at *ArrayType) Traverse(fn func(AST) bool) {
    method Copy (line 1378) | func (at *ArrayType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 1400) | func (at *ArrayType) GoString() string {
    method goString (line 1404) | func (at *ArrayType) goString(indent int, field string) string {
  type FunctionType (line 1411) | type FunctionType struct
    method print (line 1421) | func (ft *FunctionType) print(ps *printState) {
    method printInner (line 1441) | func (ft *FunctionType) printInner(ps *printState) {
    method printArgs (line 1447) | func (ft *FunctionType) printArgs(ps *printState) {
    method Traverse (line 1499) | func (ft *FunctionType) Traverse(fn func(AST) bool) {
    method Copy (line 1510) | func (ft *FunctionType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 1548) | func (ft *FunctionType) GoString() string {
    method goString (line 1552) | func (ft *FunctionType) goString(indent int, field string) string {
  type FunctionParam (line 1579) | type FunctionParam struct
    method print (line 1583) | func (fp *FunctionParam) print(ps *printState) {
    method Traverse (line 1597) | func (fp *FunctionParam) Traverse(fn func(AST) bool) {
    method Copy (line 1601) | func (fp *FunctionParam) Copy(fn func(AST) AST, skip func(AST) bool) A...
    method GoString (line 1608) | func (fp *FunctionParam) GoString() string {
    method goString (line 1612) | func (fp *FunctionParam) goString(indent int, field string) string {
    method prec (line 1616) | func (fp *FunctionParam) prec() precedence {
  type PtrMem (line 1621) | type PtrMem struct
    method print (line 1626) | func (pm *PtrMem) print(ps *printState) {
    method printInner (line 1634) | func (pm *PtrMem) printInner(ps *printState) {
    method Traverse (line 1642) | func (pm *PtrMem) Traverse(fn func(AST) bool) {
    method Copy (line 1649) | func (pm *PtrMem) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 1671) | func (pm *PtrMem) GoString() string {
    method goString (line 1675) | func (pm *PtrMem) goString(indent int, field string) string {
  type FixedType (line 1682) | type FixedType struct
    method print (line 1688) | func (ft *FixedType) print(ps *printState) {
    method Traverse (line 1705) | func (ft *FixedType) Traverse(fn func(AST) bool) {
    method Copy (line 1711) | func (ft *FixedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 1726) | func (ft *FixedType) GoString() string {
    method goString (line 1730) | func (ft *FixedType) goString(indent int, field string) string {
  type BinaryFP (line 1737) | type BinaryFP struct
    method print (line 1742) | func (bfp *BinaryFP) print(ps *printState) {
    method Traverse (line 1746) | func (bfp *BinaryFP) Traverse(fn func(AST) bool) {
    method Copy (line 1750) | func (bfp *BinaryFP) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 1757) | func (bfp *BinaryFP) GoString() string {
    method goString (line 1761) | func (bfp *BinaryFP) goString(indent int, field string) string {
  type BitIntType (line 1766) | type BitIntType struct
    method print (line 1771) | func (bt *BitIntType) print(ps *printState) {
    method Traverse (line 1781) | func (bt *BitIntType) Traverse(fn func(AST) bool) {
    method Copy (line 1787) | func (bt *BitIntType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 1802) | func (bt *BitIntType) GoString() string {
    method goString (line 1806) | func (bt *BitIntType) goString(indent int, field string) string {
  type VectorType (line 1813) | type VectorType struct
    method print (line 1818) | func (vt *VectorType) print(ps *printState) {
    method printInner (line 1826) | func (vt *VectorType) printInner(ps *printState) {
    method Traverse (line 1838) | func (vt *VectorType) Traverse(fn func(AST) bool) {
    method Copy (line 1845) | func (vt *VectorType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 1867) | func (vt *VectorType) GoString() string {
    method goString (line 1871) | func (vt *VectorType) goString(indent int, field string) string {
  type ElaboratedType (line 1878) | type ElaboratedType struct
    method print (line 1883) | func (et *ElaboratedType) print(ps *printState) {
    method Traverse (line 1889) | func (et *ElaboratedType) Traverse(fn func(AST) bool) {
    method Copy (line 1895) | func (et *ElaboratedType) Copy(fn func(AST) AST, skip func(AST) bool) ...
    method GoString (line 1910) | func (et *ElaboratedType) GoString() string {
    method goString (line 1914) | func (et *ElaboratedType) goString(indent int, field string) string {
  type Decltype (line 1920) | type Decltype struct
    method print (line 1924) | func (dt *Decltype) print(ps *printState) {
    method Traverse (line 1934) | func (dt *Decltype) Traverse(fn func(AST) bool) {
    method Copy (line 1940) | func (dt *Decltype) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 1955) | func (dt *Decltype) GoString() string {
    method goString (line 1959) | func (dt *Decltype) goString(indent int, field string) string {
  type Operator (line 1965) | type Operator struct
    method print (line 1970) | func (op *Operator) print(ps *printState) {
    method Traverse (line 1980) | func (op *Operator) Traverse(fn func(AST) bool) {
    method Copy (line 1984) | func (op *Operator) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 1991) | func (op *Operator) GoString() string {
    method goString (line 1995) | func (op *Operator) goString(indent int, field string) string {
    method prec (line 1999) | func (op *Operator) prec() precedence {
  type Constructor (line 2004) | type Constructor struct
    method print (line 2009) | func (c *Constructor) print(ps *printState) {
    method Traverse (line 2014) | func (c *Constructor) Traverse(fn func(AST) bool) {
    method Copy (line 2023) | func (c *Constructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 2048) | func (c *Constructor) GoString() string {
    method goString (line 2052) | func (c *Constructor) goString(indent int, field string) string {
  type Destructor (line 2063) | type Destructor struct
    method print (line 2067) | func (d *Destructor) print(ps *printState) {
    method Traverse (line 2072) | func (d *Destructor) Traverse(fn func(AST) bool) {
    method Copy (line 2078) | func (d *Destructor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 2093) | func (d *Destructor) GoString() string {
    method goString (line 2097) | func (d *Destructor) goString(indent int, field string) string {
  type GlobalCDtor (line 2102) | type GlobalCDtor struct
    method print (line 2107) | func (gcd *GlobalCDtor) print(ps *printState) {
    method Traverse (line 2118) | func (gcd *GlobalCDtor) Traverse(fn func(AST) bool) {
    method Copy (line 2124) | func (gcd *GlobalCDtor) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 2139) | func (gcd *GlobalCDtor) GoString() string {
    method goString (line 2143) | func (gcd *GlobalCDtor) goString(indent int, field string) string {
  type TaggedName (line 2149) | type TaggedName struct
    method print (line 2154) | func (t *TaggedName) print(ps *printState) {
    method Traverse (line 2161) | func (t *TaggedName) Traverse(fn func(AST) bool) {
    method Copy (line 2168) | func (t *TaggedName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 2190) | func (t *TaggedName) GoString() string {
    method goString (line 2194) | func (t *TaggedName) goString(indent int, field string) string {
  type PackExpansion (line 2201) | type PackExpansion struct
    method print (line 2206) | func (pe *PackExpansion) print(ps *printState) {
    method Traverse (line 2221) | func (pe *PackExpansion) Traverse(fn func(AST) bool) {
    method Copy (line 2228) | func (pe *PackExpansion) Copy(fn func(AST) AST, skip func(AST) bool) A...
    method GoString (line 2243) | func (pe *PackExpansion) GoString() string {
    method goString (line 2247) | func (pe *PackExpansion) goString(indent int, field string) string {
  type ArgumentPack (line 2253) | type ArgumentPack struct
    method print (line 2257) | func (ap *ArgumentPack) print(ps *printState) {
    method Traverse (line 2266) | func (ap *ArgumentPack) Traverse(fn func(AST) bool) {
    method Copy (line 2274) | func (ap *ArgumentPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 2299) | func (ap *ArgumentPack) GoString() string {
    method goString (line 2303) | func (ap *ArgumentPack) goString(indent int, field string) string {
  type SizeofPack (line 2316) | type SizeofPack struct
    method print (line 2320) | func (sp *SizeofPack) print(ps *printState) {
    method Traverse (line 2331) | func (sp *SizeofPack) Traverse(fn func(AST) bool) {
    method Copy (line 2336) | func (sp *SizeofPack) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 2347) | func (sp *SizeofPack) GoString() string {
    method goString (line 2351) | func (sp *SizeofPack) goString(indent int, field string) string {
  type SizeofArgs (line 2357) | type SizeofArgs struct
    method print (line 2361) | func (sa *SizeofArgs) print(ps *printState) {
    method Traverse (line 2375) | func (sa *SizeofArgs) Traverse(fn func(AST) bool) {
    method Copy (line 2383) | func (sa *SizeofArgs) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 2408) | func (sa *SizeofArgs) GoString() string {
    method goString (line 2412) | func (sa *SizeofArgs) goString(indent int, field string) string {
  type TemplateParamName (line 2429) | type TemplateParamName struct
    method print (line 2434) | func (tpn *TemplateParamName) print(ps *printState) {
    method Traverse (line 2445) | func (tpn *TemplateParamName) Traverse(fn func(AST) bool) {
    method Copy (line 2449) | func (tpn *TemplateParamName) Copy(fn func(AST) AST, skip func(AST) bo...
    method GoString (line 2456) | func (tpn *TemplateParamName) GoString() string {
    method goString (line 2460) | func (tpn *TemplateParamName) goString(indent int, field string) string {
  type TypeTemplateParam (line 2466) | type TypeTemplateParam struct
    method print (line 2470) | func (ttp *TypeTemplateParam) print(ps *printState) {
    method Traverse (line 2484) | func (ttp *TypeTemplateParam) Traverse(fn func(AST) bool) {
    method Copy (line 2490) | func (ttp *TypeTemplateParam) Copy(fn func(AST) AST, skip func(AST) bo...
    method GoString (line 2505) | func (ttp *TypeTemplateParam) GoString() string {
    method goString (line 2509) | func (ttp *TypeTemplateParam) goString(indent int, field string) string {
  type NonTypeTemplateParam (line 2516) | type NonTypeTemplateParam struct
    method print (line 2521) | func (nttp *NonTypeTemplateParam) print(ps *printState) {
    method printInner (line 2533) | func (nttp *NonTypeTemplateParam) printInner(ps *printState) {
    method Traverse (line 2537) | func (nttp *NonTypeTemplateParam) Traverse(fn func(AST) bool) {
    method Copy (line 2544) | func (nttp *NonTypeTemplateParam) Copy(fn func(AST) AST, skip func(AST...
    method GoString (line 2566) | func (nttp *NonTypeTemplateParam) GoString() string {
    method goString (line 2570) | func (nttp *NonTypeTemplateParam) goString(indent int, field string) s...
  type TemplateTemplateParam (line 2578) | type TemplateTemplateParam struct
    method print (line 2584) | func (ttp *TemplateTemplateParam) print(ps *printState) {
    method Traverse (line 2618) | func (ttp *TemplateTemplateParam) Traverse(fn func(AST) bool) {
    method Copy (line 2630) | func (ttp *TemplateTemplateParam) Copy(fn func(AST) AST, skip func(AST...
    method GoString (line 2680) | func (ttp *TemplateTemplateParam) GoString() string {
    method goString (line 2684) | func (ttp *TemplateTemplateParam) goString(indent int, field string) s...
  type ConstrainedTypeTemplateParam (line 2705) | type ConstrainedTypeTemplateParam struct
    method print (line 2710) | func (cttp *ConstrainedTypeTemplateParam) print(ps *printState) {
    method printInner (line 2720) | func (cttp *ConstrainedTypeTemplateParam) printInner(ps *printState) {
    method Traverse (line 2724) | func (cttp *ConstrainedTypeTemplateParam) Traverse(fn func(AST) bool) {
    method Copy (line 2731) | func (cttp *ConstrainedTypeTemplateParam) Copy(fn func(AST) AST, skip ...
    method GoString (line 2753) | func (cttp *ConstrainedTypeTemplateParam) GoString() string {
    method goString (line 2757) | func (cttp *ConstrainedTypeTemplateParam) goString(indent int, field s...
  type TemplateParamPack (line 2765) | type TemplateParamPack struct
    method print (line 2769) | func (tpp *TemplateParamPack) print(ps *printState) {
    method printInner (line 2789) | func (tpp *TemplateParamPack) printInner(ps *printState) {
    method Traverse (line 2796) | func (tpp *TemplateParamPack) Traverse(fn func(AST) bool) {
    method Copy (line 2802) | func (tpp *TemplateParamPack) Copy(fn func(AST) AST, skip func(AST) bo...
    method GoString (line 2817) | func (tpp *TemplateParamPack) GoString() string {
    method goString (line 2821) | func (tpp *TemplateParamPack) goString(indent int, field string) string {
  type Cast (line 2827) | type Cast struct
    method print (line 2831) | func (c *Cast) print(ps *printState) {
    method Traverse (line 2836) | func (c *Cast) Traverse(fn func(AST) bool) {
    method Copy (line 2842) | func (c *Cast) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 2857) | func (c *Cast) GoString() string {
    method goString (line 2861) | func (c *Cast) goString(indent int, field string) string {
    method prec (line 2866) | func (c *Cast) prec() precedence {
  function parenthesize (line 2872) | func parenthesize(ps *printState, val AST) {
  type Nullary (line 2898) | type Nullary struct
    method print (line 2902) | func (n *Nullary) print(ps *printState) {
    method Traverse (line 2910) | func (n *Nullary) Traverse(fn func(AST) bool) {
    method Copy (line 2916) | func (n *Nullary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 2931) | func (n *Nullary) GoString() string {
    method goString (line 2935) | func (n *Nullary) goString(indent int, field string) string {
  type Unary (line 2941) | type Unary struct
    method print (line 2948) | func (u *Unary) print(ps *printState) {
    method Traverse (line 3048) | func (u *Unary) Traverse(fn func(AST) bool) {
    method Copy (line 3055) | func (u *Unary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 3077) | func (u *Unary) GoString() string {
    method goString (line 3081) | func (u *Unary) goString(indent int, field string) string {
    method prec (line 3094) | func (u *Unary) prec() precedence {
  function isDesignatedInitializer (line 3103) | func isDesignatedInitializer(x AST) bool {
  type Binary (line 3127) | type Binary struct
    method print (line 3133) | func (b *Binary) print(ps *printState) {
    method Traverse (line 3295) | func (b *Binary) Traverse(fn func(AST) bool) {
    method Copy (line 3303) | func (b *Binary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 3329) | func (b *Binary) GoString() string {
    method goString (line 3333) | func (b *Binary) goString(indent int, field string) string {
    method prec (line 3340) | func (b *Binary) prec() precedence {
  type Trinary (line 3348) | type Trinary struct
    method print (line 3355) | func (t *Trinary) print(ps *printState) {
    method Traverse (line 3445) | func (t *Trinary) Traverse(fn func(AST) bool) {
    method Copy (line 3454) | func (t *Trinary) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 3484) | func (t *Trinary) GoString() string {
    method goString (line 3488) | func (t *Trinary) goString(indent int, field string) string {
  type Fold (line 3497) | type Fold struct
    method print (line 3504) | func (f *Fold) print(ps *printState) {
    method Traverse (line 3566) | func (f *Fold) Traverse(fn func(AST) bool) {
    method Copy (line 3576) | func (f *Fold) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 3605) | func (f *Fold) GoString() string {
    method goString (line 3609) | func (f *Fold) goString(indent int, field string) string {
  type Subobject (line 3627) | type Subobject struct
    method print (line 3635) | func (so *Subobject) print(ps *printState) {
    method Traverse (line 3642) | func (so *Subobject) Traverse(fn func(AST) bool) {
    method Copy (line 3649) | func (so *Subobject) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 3677) | func (so *Subobject) GoString() string {
    method goString (line 3681) | func (so *Subobject) goString(indent int, field string) string {
  type PtrMemCast (line 3700) | type PtrMemCast struct
    method print (line 3706) | func (pmc *PtrMemCast) print(ps *printState) {
    method Traverse (line 3714) | func (pmc *PtrMemCast) Traverse(fn func(AST) bool) {
    method Copy (line 3721) | func (pmc *PtrMemCast) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 3747) | func (pmc *PtrMemCast) GoString() string {
    method goString (line 3751) | func (pmc *PtrMemCast) goString(indent int, field string) string {
  type New (line 3760) | type New struct
    method print (line 3767) | func (n *New) print(ps *printState) {
    method Traverse (line 3792) | func (n *New) Traverse(fn func(AST) bool) {
    method Copy (line 3805) | func (n *New) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 3841) | func (n *New) GoString() string {
    method goString (line 3845) | func (n *New) goString(indent int, field string) string {
  type Literal (line 3864) | type Literal struct
    method print (line 3889) | func (l *Literal) print(ps *printState) {
    method Traverse (line 3936) | func (l *Literal) Traverse(fn func(AST) bool) {
    method Copy (line 3942) | func (l *Literal) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 3957) | func (l *Literal) GoString() string {
    method goString (line 3961) | func (l *Literal) goString(indent int, field string) string {
    method prec (line 3971) | func (l *Literal) prec() precedence {
  type StringLiteral (line 3976) | type StringLiteral struct
    method print (line 3980) | func (sl *StringLiteral) print(ps *printState) {
    method Traverse (line 3986) | func (sl *StringLiteral) Traverse(fn func(AST) bool) {
    method Copy (line 3992) | func (sl *StringLiteral) Copy(fn func(AST) AST, skip func(AST) bool) A...
    method GoString (line 4007) | func (sl *StringLiteral) GoString() string {
    method goString (line 4011) | func (sl *StringLiteral) goString(indent int, field string) string {
  type LambdaExpr (line 4017) | type LambdaExpr struct
    method print (line 4021) | func (le *LambdaExpr) print(ps *printState) {
    method Traverse (line 4029) | func (le *LambdaExpr) Traverse(fn func(AST) bool) {
    method Copy (line 4035) | func (le *LambdaExpr) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4050) | func (le *LambdaExpr) GoString() string {
    method goString (line 4054) | func (le *LambdaExpr) goString(indent int, field string) string {
  type ExprList (line 4061) | type ExprList struct
    method print (line 4065) | func (el *ExprList) print(ps *printState) {
    method Traverse (line 4069) | func (el *ExprList) Traverse(fn func(AST) bool) {
    method Copy (line 4077) | func (el *ExprList) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4102) | func (el *ExprList) GoString() string {
    method goString (line 4106) | func (el *ExprList) goString(indent int, field string) string {
    method prec (line 4118) | func (el *ExprList) prec() precedence {
  type InitializerList (line 4124) | type InitializerList struct
    method print (line 4129) | func (il *InitializerList) print(ps *printState) {
    method printAsString (line 4150) | func (il *InitializerList) printAsString(ps *printState) bool {
    method Traverse (line 4229) | func (il *InitializerList) Traverse(fn func(AST) bool) {
    method Copy (line 4238) | func (il *InitializerList) Copy(fn func(AST) AST, skip func(AST) bool)...
    method GoString (line 4263) | func (il *InitializerList) GoString() string {
    method goString (line 4267) | func (il *InitializerList) goString(indent int, field string) string {
  type DefaultArg (line 4279) | type DefaultArg struct
    method print (line 4284) | func (da *DefaultArg) print(ps *printState) {
    method Traverse (line 4291) | func (da *DefaultArg) Traverse(fn func(AST) bool) {
    method Copy (line 4297) | func (da *DefaultArg) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4312) | func (da *DefaultArg) GoString() string {
    method goString (line 4316) | func (da *DefaultArg) goString(indent int, field string) string {
  type Closure (line 4322) | type Closure struct
    method print (line 4330) | func (cl *Closure) print(ps *printState) {
    method printTypes (line 4346) | func (cl *Closure) printTypes(ps *printState) {
    method Traverse (line 4374) | func (cl *Closure) Traverse(fn func(AST) bool) {
    method Copy (line 4391) | func (cl *Closure) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4455) | func (cl *Closure) GoString() string {
    method goString (line 4459) | func (cl *Closure) goString(indent int, field string) string {
  type StructuredBindings (line 4498) | type StructuredBindings struct
    method print (line 4502) | func (sb *StructuredBindings) print(ps *printState) {
    method Traverse (line 4508) | func (sb *StructuredBindings) Traverse(fn func(AST) bool) {
    method Copy (line 4516) | func (sb *StructuredBindings) Copy(fn func(AST) AST, skip func(AST) bo...
    method GoString (line 4541) | func (sb *StructuredBindings) GoString() string {
    method goString (line 4545) | func (sb *StructuredBindings) goString(indent int, field string) string {
  type UnnamedType (line 4556) | type UnnamedType struct
    method print (line 4560) | func (ut *UnnamedType) print(ps *printState) {
    method Traverse (line 4572) | func (ut *UnnamedType) Traverse(fn func(AST) bool) {
    method Copy (line 4576) | func (ut *UnnamedType) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4583) | func (ut *UnnamedType) GoString() string {
    method goString (line 4587) | func (ut *UnnamedType) goString(indent int, field string) string {
  type UnnamedEnum (line 4592) | type UnnamedEnum struct
    method print (line 4597) | func (ue *UnnamedEnum) print(ps *printState) {
    method Traverse (line 4605) | func (ue *UnnamedEnum) Traverse(fn func(AST) bool) {
    method Copy (line 4612) | func (ue *UnnamedEnum) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4634) | func (ue *UnnamedEnum) GoString() string {
    method goString (line 4638) | func (ue *UnnamedEnum) goString(indent int, field string) string {
  type Clone (line 4645) | type Clone struct
    method print (line 4650) | func (c *Clone) print(ps *printState) {
    method Traverse (line 4662) | func (c *Clone) Traverse(fn func(AST) bool) {
    method Copy (line 4668) | func (c *Clone) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4683) | func (c *Clone) GoString() string {
    method goString (line 4687) | func (c *Clone) goString(indent int, field string) string {
  type Special (line 4694) | type Special struct
    method print (line 4699) | func (s *Special) print(ps *printState) {
    method Traverse (line 4713) | func (s *Special) Traverse(fn func(AST) bool) {
    method Copy (line 4719) | func (s *Special) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4734) | func (s *Special) GoString() string {
    method goString (line 4738) | func (s *Special) goString(indent int, field string) string {
  type Special2 (line 4744) | type Special2 struct
    method print (line 4751) | func (s *Special2) print(ps *printState) {
    method Traverse (line 4758) | func (s *Special2) Traverse(fn func(AST) bool) {
    method Copy (line 4765) | func (s *Special2) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4787) | func (s *Special2) GoString() string {
    method goString (line 4791) | func (s *Special2) goString(indent int, field string) string {
  type EnableIf (line 4798) | type EnableIf struct
    method print (line 4803) | func (ei *EnableIf) print(ps *printState) {
    method Traverse (line 4810) | func (ei *EnableIf) Traverse(fn func(AST) bool) {
    method Copy (line 4819) | func (ei *EnableIf) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4848) | func (ei *EnableIf) GoString() string {
    method goString (line 4852) | func (ei *EnableIf) goString(indent int, field string) string {
  type ModuleName (line 4868) | type ModuleName struct
    method print (line 4874) | func (mn *ModuleName) print(ps *printState) {
    method Traverse (line 4886) | func (mn *ModuleName) Traverse(fn func(AST) bool) {
    method Copy (line 4895) | func (mn *ModuleName) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4920) | func (mn *ModuleName) GoString() string {
    method goString (line 4924) | func (mn *ModuleName) goString(indent int, field string) string {
  type ModuleEntity (line 4937) | type ModuleEntity struct
    method print (line 4942) | func (me *ModuleEntity) print(ps *printState) {
    method Traverse (line 4948) | func (me *ModuleEntity) Traverse(fn func(AST) bool) {
    method Copy (line 4955) | func (me *ModuleEntity) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 4977) | func (me *ModuleEntity) GoString() string {
    method goString (line 4981) | func (me *ModuleEntity) goString(indent int, field string) string {
  type Friend (line 4988) | type Friend struct
    method print (line 4992) | func (f *Friend) print(ps *printState) {
    method Traverse (line 5002) | func (f *Friend) Traverse(fn func(AST) bool) {
    method Copy (line 5008) | func (f *Friend) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 5023) | func (f *Friend) GoString() string {
    method goString (line 5027) | func (f *Friend) goString(indent int, field string) string {
  type Constraint (line 5036) | type Constraint struct
    method print (line 5042) | func (c *Constraint) print(ps *printState) {
    method Traverse (line 5054) | func (c *Constraint) Traverse(fn func(AST) bool) {
    method Copy (line 5061) | func (c *Constraint) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 5087) | func (c *Constraint) GoString() string {
    method goString (line 5091) | func (c *Constraint) goString(indent int, field string) string {
  type RequiresExpr (line 5099) | type RequiresExpr struct
    method print (line 5104) | func (re *RequiresExpr) print(ps *printState) {
    method Traverse (line 5121) | func (re *RequiresExpr) Traverse(fn func(AST) bool) {
    method Copy (line 5132) | func (re *RequiresExpr) Copy(fn func(AST) AST, skip func(AST) bool) AST {
    method GoString (line 5175) | func (re *RequiresExpr) GoString() string {
    method goString (line 5179) | func (re *RequiresExpr) goString(indent int, field string) string {
  type ExprRequirement (line 5204) | type ExprRequirement struct
    method print (line 5210) | func (er *ExprRequirement) print(ps *printState) {
    method Traverse (line 5229) | func (er *ExprRequirement) Traverse(fn func(AST) bool) {
    method Copy (line 5238) | func (er *ExprRequirement) Copy(fn func(AST) AST, skip func(AST) bool)...
    method GoString (line 5263) | func (er *ExprRequirement) GoString() string {
    method goString (line 5267) | func (er *ExprRequirement) goString(indent int, field string) string {
  type TypeRequirement (line 5280) | type TypeRequirement struct
    method print (line 5284) | func (tr *TypeRequirement) print(ps *printState) {
    method Traverse (line 5290) | func (tr *TypeRequirement) Traverse(fn func(AST) bool) {
    method Copy (line 5296) | func (tr *TypeRequirement) Copy(fn func(AST) AST, skip func(AST) bool)...
    method GoString (line 5311) | func (tr *TypeRequirement) GoString() string {
    method goString (line 5315) | func (tr *TypeRequirement) goString(indent int, field string) string {
  type NestedRequirement (line 5321) | type NestedRequirement struct
    method print (line 5325) | func (nr *NestedRequirement) print(ps *printState) {
    method Traverse (line 5331) | func (nr *NestedRequirement) Traverse(fn func(AST) bool) {
    method Copy (line 5337) | func (nr *NestedRequirement) Copy(fn func(AST) AST, skip func(AST) boo...
    method GoString (line 5352) | func (nr *NestedRequirement) GoString() string {
    method goString (line 5356) | func (nr *NestedRequirement) goString(indent int, field string) string {
  type ExplicitObjectParameter (line 5362) | type ExplicitObjectParameter struct
    method print (line 5366) | func (eop *ExplicitObjectParameter) print(ps *printState) {
    method Traverse (line 5371) | func (eop *ExplicitObjectParameter) Traverse(fn func(AST) bool) {
    method Copy (line 5377) | func (eop *ExplicitObjectParameter) Copy(fn func(AST) AST, skip func(A...
    method GoString (line 5392) | func (eop *ExplicitObjectParameter) GoString() string {
    method goString (line 5396) | func (eop *ExplicitObjectParameter) goString(indent int, field string)...
  type innerPrinter (line 5416) | type innerPrinter interface

FILE: ast_test.go
  function TestASTToString (line 12) | func TestASTToString(t *testing.T) {

FILE: c++filt.go
  function flagUsage (line 25) | func flagUsage() {
  function usage (line 29) | func usage(w io.Writer, status int) {
  constant symbolChars (line 56) | symbolChars = "_$."
  function main (line 58) | func main() {
  function doDemangle (line 124) | func doDemangle(out *bufio.Writer, name string) {
  function options (line 145) | func options() []demangle.Option {

FILE: cases_test.go
  function TestCases (line 62) | func TestCases(t *testing.T) {
  function readCases (line 157) | func readCases(t testing.TB) [][2]string {
  function readCasesString (line 219) | func readCasesString(t testing.TB, r *bufio.Reader, fn string, lineno *i...
  function readCasesUnquotedByte (line 303) | func readCasesUnquotedByte(t testing.TB, r *bufio.Reader, fn string, lin...
  function readCasesUnquotedByteNoEOF (line 344) | func readCasesUnquotedByteNoEOF(t testing.TB, r *bufio.Reader, fn string...
  function readCasesByte (line 355) | func readCasesByte(t testing.TB, r *bufio.Reader, fn string, lineno int)...
  function readCasesByteNoEOF (line 368) | func readCasesByteNoEOF(t testing.TB, r *bufio.Reader, fn string, lineno...

FILE: demangle.go
  type Option (line 26) | type Option
  constant NoParams (line 34) | NoParams Option = iota
  constant NoTemplateParams (line 38) | NoTemplateParams
  constant NoEnclosingParams (line 43) | NoEnclosingParams
  constant NoClones (line 47) | NoClones
  constant NoRust (line 52) | NoRust
  constant Verbose (line 55) | Verbose
  constant LLVMStyle (line 61) | LLVMStyle
  constant maxLengthShift (line 65) | maxLengthShift = 16
  constant maxLengthMask (line 68) | maxLengthMask = 0x1f << maxLengthShift
  function MaxLength (line 75) | func MaxLength(pow int) Option {
  function isMaxLength (line 83) | func isMaxLength(opt Option) bool {
  function maxLength (line 88) | func maxLength(opt Option) int {
  function Filter (line 95) | func Filter(name string, options ...Option) string {
  function ToString (line 107) | func ToString(name string, options ...Option) (string, error) {
  function ToAST (line 152) | func ToAST(name string, options ...Option) (AST, error) {
  function globalCDtorName (line 209) | func globalCDtorName(name string, options ...Option) (AST, error) {
  function allocToken (line 251) | func allocToken(name string, options ...Option) (AST, error) {
  function doDemangle (line 279) | func doDemangle(name string, options ...Option) (ret AST, err error) {
  type state (line 333) | type state struct
    method copy (line 354) | func (st *state) copy() *state {
    method fail (line 361) | func (st *state) fail(err string) {
    method failEarlier (line 367) | func (st *state) failEarlier(err string, dec int) {
    method advance (line 375) | func (st *state) advance(add int) {
    method checkChar (line 385) | func (st *state) checkChar(c byte) {
    method encoding (line 429) | func (st *state) encoding(params bool, local forLocalNameType) AST {
    method taggedName (line 625) | func (st *state) taggedName(a AST) AST {
    method name (line 649) | func (st *state) name() (AST, bool) {
    method nestedName (line 741) | func (st *state) nestedName() (AST, bool) {
    method prefix (line 783) | func (st *state) prefix() AST {
    method unqualifiedName (line 988) | func (st *state) unqualifiedName(module AST) (r AST, isCast bool) {
    method sourceName (line 1083) | func (st *state) sourceName() AST {
    method moduleName (line 1118) | func (st *state) moduleName(parent AST) AST {
    method number (line 1141) | func (st *state) number() int {
    method seqID (line 1171) | func (st *state) seqID(eofOK bool) int {
    method operatorName (line 1304) | func (st *state) operatorName(inExpression bool) (AST, int) {
    method localName (line 1344) | func (st *state) localName() (AST, bool) {
    method javaResource (line 1373) | func (st *state) javaResource() AST {
    method specialName (line 1432) | func (st *state) specialName() AST {
    method callOffset (line 1563) | func (st *state) callOffset(c byte) {
    method demangleType (line 1635) | func (st *state) demangleType(isCast bool) AST {
    method demangleCastTemplateArgs (line 2060) | func (st *state) demangleCastTemplateArgs(tp AST, addSubst bool) AST {
    method cvQualifiers (line 2136) | func (st *state) cvQualifiers() AST {
    method refQualifier (line 2187) | func (st *state) refQualifier() string {
    method parmlist (line 2204) | func (st *state) parmlist(explicitObjectParameter bool) []AST {
    method functionType (line 2250) | func (st *state) functionType() AST {
    method bareFunctionType (line 2271) | func (st *state) bareFunctionType(hasReturnType, explicitObjectParamet...
    method arrayType (line 2292) | func (st *state) arrayType(isCast bool) AST {
    method vectorType (line 2335) | func (st *state) vectorType(isCast bool) AST {
    method pointerToMemberType (line 2362) | func (st *state) pointerToMemberType(isCast bool) AST {
    method compactNumber (line 2390) | func (st *state) compactNumber() int {
    method templateParam (line 2420) | func (st *state) templateParam() AST {
    method setTemplate (line 2472) | func (st *state) setTemplate(a AST, tmpl *Template) {
    method clearTemplateArgs (line 2521) | func (st *state) clearTemplateArgs(args []AST) {
    method templateArgs (line 2532) | func (st *state) templateArgs() ([]AST, AST) {
    method templateArg (line 2565) | func (st *state) templateArg(prev []AST) AST {
    method maybeAddConstraint (line 2622) | func (st *state) maybeAddConstraint(a, constraint AST) AST {
    method template (line 2634) | func (st *state) template(name AST) AST {
    method exprList (line 2641) | func (st *state) exprList(stop byte) AST {
    method expression (line 2720) | func (st *state) expression() AST {
    method subobject (line 2979) | func (st *state) subobject() AST {
    method unresolvedName (line 3019) | func (st *state) unresolvedName() AST {
    method baseUnresolvedName (line 3096) | func (st *state) baseUnresolvedName() AST {
    method requiresExpr (line 3130) | func (st *state) requiresExpr() AST {
    method exprPrimary (line 3208) | func (st *state) exprPrimary() AST {
    method discriminator (line 3279) | func (st *state) discriminator(a AST) AST {
    method closureTypeName (line 3318) | func (st *state) closureTypeName() AST {
    method templateParamDecl (line 3386) | func (st *state) templateParamDecl() (AST, AST) {
    method unnamedTypeName (line 3493) | func (st *state) unnamedTypeName() AST {
    method unnamedEnum (line 3504) | func (st *state) unnamedEnum() AST {
    method constraintExpr (line 3519) | func (st *state) constraintExpr() AST {
    method cloneSuffix (line 3531) | func (st *state) cloneSuffix(a AST) AST {
    method substitution (line 3626) | func (st *state) substitution(forPrefix bool) AST {
    method findArgumentPack (line 3917) | func (st *state) findArgumentPack(a AST) *ArgumentPack {
  type demangleErr (line 394) | type demangleErr struct
    method Error (line 400) | func (de demangleErr) Error() string {
  function adjustErr (line 406) | func adjustErr(err error, adj int) error {
  type forLocalNameType (line 417) | type forLocalNameType
  constant forLocalName (line 420) | forLocalName forLocalNameType = iota
  constant notForLocalName (line 421) | notForLocalName
  function hasReturnType (line 589) | func hasReturnType(a AST) bool {
  function isCDtorConversion (line 611) | func isCDtorConversion(a AST) bool {
  type operator (line 1206) | type operator struct
  function mergeQualifiers (line 2096) | func mergeQualifiers(q1AST, q2AST AST) AST {
  type substitutions (line 3552) | type substitutions
    method add (line 3555) | func (subs *substitutions) add(a AST) {
  function isDigit (line 3786) | func isDigit(c byte) bool {
  function isUpper (line 3791) | func isUpper(c byte) bool {
  function isLower (line 3796) | func isLower(c byte) bool {
  function simplify (line 3802) | func simplify(a AST) AST {
  function simplifyOne (line 3819) | func simplifyOne(a AST) AST {

FILE: demangle_test.go
  function TestDemangler (line 412) | func TestDemangler(t *testing.T) {
  function TestFailure (line 600) | func TestFailure(t *testing.T) {
  function TestMaxLength (line 628) | func TestMaxLength(t *testing.T) {
  function TestOptionsSlice (line 644) | func TestOptionsSlice(t *testing.T) {

FILE: expected_test.go
  constant filename (line 18) | filename = "testdata/demangle-expected"
  function TestExpected (line 63) | func TestExpected(t *testing.T) {
  function oneTest (line 103) | func oneTest(t *testing.T, report int, input, expect string, params bool) {
  function getLine (line 165) | func getLine(t testing.TB, scanner *bufio.Scanner, lineno *int) string {
  function getOptLine (line 175) | func getOptLine(t testing.TB, scanner *bufio.Scanner, lineno *int) (stri...
  function skipExpectedTest (line 190) | func skipExpectedTest(t testing.TB, format, input string, report int) (s...

FILE: fuzz_test.go
  function FuzzDemangle (line 14) | func FuzzDemangle(f *testing.F) {
  function FuzzRustDemangle (line 79) | func FuzzRustDemangle(f *testing.F) {

FILE: rust.go
  function rustToString (line 16) | func rustToString(name string, options []Option) (ret string, err error) {
  type rustState (line 82) | type rustState struct
    method fail (line 95) | func (rst *rustState) fail(err string) {
    method advance (line 100) | func (rst *rustState) advance(add int) {
    method checkChar (line 110) | func (rst *rustState) checkChar(c byte) {
    method writeByte (line 118) | func (rst *rustState) writeByte(c byte) {
    method writeString (line 131) | func (rst *rustState) writeString(s string) {
    method symbolName (line 151) | func (rst *rustState) symbolName() {
    method path (line 184) | func (rst *rustState) path(needsSeparator bool) {
    method implPath (line 271) | func (rst *rustState) implPath() {
    method identifier (line 288) | func (rst *rustState) identifier() (int64, string) {
    method disambiguator (line 297) | func (rst *rustState) disambiguator() int64 {
    method undisambiguatedIdentifier (line 308) | func (rst *rustState) undisambiguatedIdentifier() (id string, isPunyco...
    method expandPunycode (line 348) | func (rst *rustState) expandPunycode(s string) string {
    method genericArgs (line 455) | func (rst *rustState) genericArgs() {
    method genericArg (line 481) | func (rst *rustState) genericArg() {
    method binder (line 499) | func (rst *rustState) binder() {
    method demangleType (line 537) | func (rst *rustState) demangleType() {
    method basicType (line 651) | func (rst *rustState) basicType() {
    method fnSig (line 668) | func (rst *rustState) fnSig() {
    method dynBounds (line 713) | func (rst *rustState) dynBounds() {
    method dynTrait (line 732) | func (rst *rustState) dynTrait() {
    method pathStartGenerics (line 754) | func (rst *rustState) pathStartGenerics() bool {
    method writeLifetime (line 777) | func (rst *rustState) writeLifetime(lifetime int64) {
    method demangleConst (line 803) | func (rst *rustState) demangleConst() {
    method base62Number (line 936) | func (rst *rustState) base62Number() int64 {
    method backref (line 966) | func (rst *rustState) backref(demangle func()) {
    method decimalNumber (line 999) | func (rst *rustState) decimalNumber() int {
  function oldRustToString (line 1019) | func oldRustToString(name string, options []Option) (string, bool) {

FILE: rust_expected_test.go
  constant rustFilename (line 15) | rustFilename = "testdata/rust-demangle-expected"
  function TestRustExpected (line 19) | func TestRustExpected(t *testing.T) {
  function oneRustTest (line 48) | func oneRustTest(t *testing.T, report int, input, expect string) {
  function skipExpectedRustTest (line 81) | func skipExpectedRustTest(t testing.TB, format, input string, report int...
  constant rustCheckFilename (line 98) | rustCheckFilename = "testdata/rust.test"
  function TestRustCheck (line 100) | func TestRustCheck(t *testing.T) {
  constant rustMangledTemplates (line 136) | rustMangledTemplates = "_RNCINvMNtNtNtNtCs5myfTy8mnaF_6timely8dataflow9o...
  function TestRustNoTemplaraParams (line 138) | func TestRustNoTemplaraParams(t *testing.T) {
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,845K chars).
[
  {
    "path": ".gitignore",
    "chars": 78,
    "preview": "*.o\n*.a\n*.so\n._*\n.nfs.*\na.out\n*~\n*.orig\n*.rej\n*.exe\n.*.swp\ncore\ndemangle.test\n"
  },
  {
    "path": "LICENSE",
    "chars": 1479,
    "preview": "Copyright (c) 2015 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or with"
  },
  {
    "path": "README.md",
    "chars": 107,
    "preview": "# github.com/ianlancetaylor/demangle\n\nA Go package that can be used to demangle C++ and Rust symbol names.\n"
  },
  {
    "path": "SECURITY.md",
    "chars": 686,
    "preview": "# Security Policy\n\n## Supported Versions\n\nSecurity updates are applied only to the latest release.\n\n## Reporting a Vulne"
  },
  {
    "path": "ast.go",
    "chars": 112903,
    "preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "ast_test.go",
    "chars": 902,
    "preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "c++filt.go",
    "chars": 4053,
    "preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "cases_test.go",
    "chars": 11362,
    "preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "demangle.go",
    "chars": 102646,
    "preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "demangle_test.go",
    "chars": 50930,
    "preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "expected_test.go",
    "chars": 7463,
    "preview": "// Copyright 2015 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "fuzz_test.go",
    "chars": 2455,
    "preview": "// Copyright 2025 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "go.mod",
    "chars": 51,
    "preview": "module github.com/ianlancetaylor/demangle\n\ngo 1.13\n"
  },
  {
    "path": "rust.go",
    "chars": 23888,
    "preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "rust_expected_test.go",
    "chars": 4494,
    "preview": "// Copyright 2021 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "testdata/DemangleTestCases.inc",
    "chars": 5247050,
    "preview": "// clang-format off\n{\"_Z1A\", \"A\"},\n{\"_Z1Av\", \"A()\"},\n{\"_Z1A1B1C\", \"A(B, C)\"},\n{\"_Z1fDB3_\", \"f(_BitInt(3))\"},\n{\"_Z1fDU10_"
  },
  {
    "path": "testdata/demangle-expected",
    "chars": 66919,
    "preview": "# This file holds test cases for the demangler.\n# Each test case looks like this:\n#  options\n#  input to be demangled\n# "
  },
  {
    "path": "testdata/rust-demangle-expected",
    "chars": 10127,
    "preview": "# This file holds test cases for the Rust demangler.\n# Each test case looks like this:\n#  options\n#  input to be demangl"
  },
  {
    "path": "testdata/rust.test",
    "chars": 9502,
    "preview": "RUN: llvm-cxxfilt -n  < %s | FileCheck --match-full-lines %s\n\nCHECK: a::main\n       _RNvC1a4main\n\nCHECK: hello::rust\n   "
  }
]

About this extraction

This page contains the full source code of the ianlancetaylor/demangle GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (5.4 MB), approximately 1.4M tokens, and a symbol index with 685 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!