12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327 |
- // Copyright 2015 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
-
- // Package demangle defines functions that demangle GCC/LLVM C++ symbol names.
- // This package recognizes names that were mangled according to the C++ ABI
- // defined at http://codesourcery.com/cxx-abi/.
- package demangle
-
- import (
- "errors"
- "fmt"
- "strings"
- )
-
- // ErrNotMangledName is returned by CheckedDemangle if the string does
- // not appear to be a C++ symbol name.
- var ErrNotMangledName = errors.New("not a C++ mangled name")
-
- // Option is the type of demangler options.
- type Option int
-
- const (
- // The NoParams option disables demangling of function parameters.
- NoParams Option = iota
-
- // The NoTemplateParams option disables demangling of template parameters.
- NoTemplateParams
-
- // The NoClones option disables inclusion of clone suffixes.
- // NoParams implies NoClones.
- NoClones
-
- // The Verbose option turns on more verbose demangling.
- Verbose
- )
-
- // Filter demangles a C++ symbol name, returning the human-readable C++ name.
- // If any error occurs during demangling, the input string is returned.
- func Filter(name string, options ...Option) string {
- ret, err := ToString(name, options...)
- if err != nil {
- return name
- }
- return ret
- }
-
- // ToString demangles a C++ symbol name, returning human-readable C++
- // name or an error.
- // If the name does not appear to be a C++ symbol name at all, the
- // error will be ErrNotMangledName.
- func ToString(name string, options ...Option) (string, error) {
- a, err := ToAST(name, options...)
- if err != nil {
- return "", err
- }
- return ASTToString(a, options...), nil
- }
-
- // ToAST demangles a C++ symbol name into an abstract syntax tree
- // representing the symbol.
- // If the NoParams option is passed, and the name has a function type,
- // the parameter types are not demangled.
- // If the name does not appear to be a C++ symbol name at all, the
- // error will be ErrNotMangledName.
- func ToAST(name string, options ...Option) (AST, error) {
- if strings.HasPrefix(name, "_Z") {
- a, err := doDemangle(name[2:], options...)
- return a, adjustErr(err, 2)
- }
-
- const prefix = "_GLOBAL_"
- if strings.HasPrefix(name, prefix) {
- // The standard demangler ignores NoParams for global
- // constructors. We are compatible.
- i := 0
- for i < len(options) {
- if options[i] == NoParams {
- options = append(options[:i], options[i+1:]...)
- } else {
- i++
- }
- }
- a, err := globalCDtorName(name[len(prefix):], options...)
- return a, adjustErr(err, len(prefix))
- }
-
- return nil, ErrNotMangledName
- }
-
- // globalCDtorName demangles a global constructor/destructor symbol name.
- // The parameter is the string following the "_GLOBAL_" prefix.
- func globalCDtorName(name string, options ...Option) (AST, error) {
- if len(name) < 4 {
- return nil, ErrNotMangledName
- }
- switch name[0] {
- case '.', '_', '$':
- default:
- return nil, ErrNotMangledName
- }
-
- var ctor bool
- switch name[1] {
- case 'I':
- ctor = true
- case 'D':
- ctor = false
- default:
- return nil, ErrNotMangledName
- }
-
- if name[2] != '_' {
- return nil, ErrNotMangledName
- }
-
- if !strings.HasPrefix(name[3:], "_Z") {
- return &GlobalCDtor{Ctor: ctor, Key: &Name{Name: name}}, nil
- } else {
- a, err := doDemangle(name[5:], options...)
- if err != nil {
- return nil, adjustErr(err, 5)
- }
- return &GlobalCDtor{Ctor: ctor, Key: a}, nil
- }
- }
-
- // The doDemangle function is the entry point into the demangler proper.
- func doDemangle(name string, options ...Option) (ret AST, err error) {
- // When the demangling routines encounter an error, they panic
- // with a value of type demangleErr.
- defer func() {
- if r := recover(); r != nil {
- if de, ok := r.(demangleErr); ok {
- ret = nil
- err = de
- return
- }
- panic(r)
- }
- }()
-
- params := true
- clones := true
- verbose := false
- for _, o := range options {
- switch o {
- case NoParams:
- params = false
- clones = false
- case NoTemplateParams:
- // This is a valid option but only affect printing of the AST.
- case NoClones:
- clones = false
- case Verbose:
- verbose = true
- default:
- return nil, fmt.Errorf("unrecognized demangler option %v", o)
- }
- }
-
- st := &state{str: name, verbose: verbose}
- a := st.encoding(params)
-
- // Accept a clone suffix.
- if clones {
- for len(st.str) > 1 && st.str[0] == '.' && (isLower(st.str[1]) || st.str[1] == '_' || isDigit(st.str[1])) {
- a = st.cloneSuffix(a)
- }
- }
-
- if clones && len(st.str) > 0 {
- st.fail("unparsed characters at end of mangled name")
- }
-
- return a, nil
- }
-
- // A state holds the current state of demangling a string.
- type state struct {
- str string // remainder of string to demangle
- verbose bool // whether to use verbose demangling
- off int // offset of str within original string
- subs substitutions // substitutions
- templates []*Template // templates being processed
- }
-
- // copy returns a copy of the current state.
- func (st *state) copy() *state {
- n := new(state)
- *n = *st
- return n
- }
-
- // fail panics with demangleErr, to be caught in doDemangle.
- func (st *state) fail(err string) {
- panic(demangleErr{err: err, off: st.off})
- }
-
- // failEarlier is like fail, but decrements the offset to indicate
- // that the point of failure occurred earlier in the string.
- func (st *state) failEarlier(err string, dec int) {
- if st.off < dec {
- panic("internal error")
- }
- panic(demangleErr{err: err, off: st.off - dec})
- }
-
- // advance advances the current string offset.
- func (st *state) advance(add int) {
- if len(st.str) < add {
- panic("internal error")
- }
- st.str = st.str[add:]
- st.off += add
- }
-
- // checkChar requires that the next character in the string be c, and
- // advances past it.
- func (st *state) checkChar(c byte) {
- if len(st.str) == 0 || st.str[0] != c {
- panic("internal error")
- }
- st.advance(1)
- }
-
- // A demangleErr is an error at a specific offset in the mangled
- // string.
- type demangleErr struct {
- err string
- off int
- }
-
- // Error implements the builtin error interface for demangleErr.
- func (de demangleErr) Error() string {
- return fmt.Sprintf("%s at %d", de.err, de.off)
- }
-
- // adjustErr adjusts the position of err, if it is a demangleErr,
- // and returns err.
- func adjustErr(err error, adj int) error {
- if err == nil {
- return nil
- }
- if de, ok := err.(demangleErr); ok {
- de.off += adj
- return de
- }
- return err
- }
-
- // encoding ::= <(function) name> <bare-function-type>
- // <(data) name>
- // <special-name>
- func (st *state) encoding(params bool) AST {
- if len(st.str) < 1 {
- st.fail("expected encoding")
- }
-
- if st.str[0] == 'G' || st.str[0] == 'T' {
- return st.specialName()
- }
-
- a := st.name()
- a = simplify(a)
-
- if !params {
- // Don't demangle the parameters.
-
- // Strip CV-qualifiers, as they apply to the 'this'
- // parameter, and are not output by the standard
- // demangler without parameters.
- if mwq, ok := a.(*MethodWithQualifiers); ok {
- a = mwq.Method
- }
-
- // If this is a local name, there may be CV-qualifiers
- // on the name that really apply to the top level, and
- // therefore must be discarded when discarding
- // parameters. This can happen when parsing a class
- // that is local to a function.
- if q, ok := a.(*Qualified); ok && q.LocalName {
- p := &q.Name
- if da, ok := (*p).(*DefaultArg); ok {
- p = &da.Arg
- }
- if mwq, ok := (*p).(*MethodWithQualifiers); ok {
- *p = mwq.Method
- }
- }
-
- return a
- }
-
- if len(st.str) == 0 || st.str[0] == 'E' {
- // There are no parameters--this is a data symbol, not
- // a function symbol.
- return a
- }
-
- check := a
- mwq, _ := check.(*MethodWithQualifiers)
- if mwq != nil {
- check = mwq.Method
- }
- template, _ := check.(*Template)
- if template != nil {
- st.templates = append(st.templates, template)
- }
-
- ft := st.bareFunctionType(hasReturnType(a))
-
- if template != nil {
- st.templates = st.templates[:len(st.templates)-1]
- }
-
- ft = simplify(ft)
-
- // Any top-level qualifiers belong to the function type.
- if mwq != nil {
- a = mwq.Method
- mwq.Method = ft
- ft = mwq
- }
- if q, ok := a.(*Qualified); ok && q.LocalName {
- p := &q.Name
- if da, ok := (*p).(*DefaultArg); ok {
- p = &da.Arg
- }
- if mwq, ok := (*p).(*MethodWithQualifiers); ok {
- *p = mwq.Method
- mwq.Method = ft
- ft = mwq
- }
- }
-
- return &Typed{Name: a, Type: ft}
- }
-
- // hasReturnType returns whether the mangled form of a will have a
- // return type.
- func hasReturnType(a AST) bool {
- switch a := a.(type) {
- case *Template:
- return !isCDtorConversion(a.Name)
- case *TypeWithQualifiers:
- return hasReturnType(a.Base)
- case *MethodWithQualifiers:
- return hasReturnType(a.Method)
- default:
- return false
- }
- }
-
- // isCDtorConversion returns when an AST is a constructor, a
- // destructor, or a conversion operator.
- func isCDtorConversion(a AST) bool {
- switch a := a.(type) {
- case *Qualified:
- return isCDtorConversion(a.Name)
- case *Constructor, *Destructor, *Cast:
- return true
- default:
- return false
- }
- }
-
- // <tagged-name> ::= <name> B <source-name>
- func (st *state) taggedName(a AST) AST {
- for len(st.str) > 0 && st.str[0] == 'B' {
- st.advance(1)
- tag := st.sourceName()
- a = &TaggedName{Name: a, Tag: tag}
- }
- return a
- }
-
- // <name> ::= <nested-name>
- // ::= <unscoped-name>
- // ::= <unscoped-template-name> <template-args>
- // ::= <local-name>
- //
- // <unscoped-name> ::= <unqualified-name>
- // ::= St <unqualified-name>
- //
- // <unscoped-template-name> ::= <unscoped-name>
- // ::= <substitution>
- func (st *state) name() AST {
- if len(st.str) < 1 {
- st.fail("expected name")
- }
- switch st.str[0] {
- case 'N':
- return st.nestedName()
- case 'Z':
- return st.localName()
- case 'U':
- return st.unqualifiedName()
- case 'S':
- if len(st.str) < 2 {
- st.advance(1)
- st.fail("expected substitution index")
- }
- var a AST
- subst := false
- if st.str[1] == 't' {
- st.advance(2)
- a = st.unqualifiedName()
- a = &Qualified{Scope: &Name{Name: "std"}, Name: a, LocalName: false}
- } else {
- a = st.substitution(false)
- subst = true
- }
- if len(st.str) > 0 && st.str[0] == 'I' {
- // This can only happen if we saw
- // <unscoped-template-name> and are about to see
- // <template-args>. <unscoped-template-name> is a
- // substitution candidate if it did not come from a
- // substitution.
- if !subst {
- st.subs.add(a)
- }
- args := st.templateArgs()
- a = &Template{Name: a, Args: args}
- }
- return a
-
- default:
- a := st.unqualifiedName()
- if len(st.str) > 0 && st.str[0] == 'I' {
- st.subs.add(a)
- args := st.templateArgs()
- a = &Template{Name: a, Args: args}
- }
- return a
- }
- }
-
- // <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
- // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
- func (st *state) nestedName() AST {
- st.checkChar('N')
- q := st.cvQualifiers()
- r := st.refQualifier()
- a := st.prefix()
- if len(q) > 0 || r != "" {
- a = &MethodWithQualifiers{Method: a, Qualifiers: q, RefQualifier: r}
- }
- if len(st.str) == 0 || st.str[0] != 'E' {
- st.fail("expected E after nested name")
- }
- st.advance(1)
- return a
- }
-
- // <prefix> ::= <prefix> <unqualified-name>
- // ::= <template-prefix> <template-args>
- // ::= <template-param>
- // ::= <decltype>
- // ::=
- // ::= <substitution>
- //
- // <template-prefix> ::= <prefix> <(template) unqualified-name>
- // ::= <template-param>
- // ::= <substitution>
- //
- // <decltype> ::= Dt <expression> E
- // ::= DT <expression> E
- func (st *state) prefix() AST {
- var a AST
-
- // The last name seen, for a constructor/destructor.
- var last AST
-
- getLast := func(a AST) AST {
- for {
- if t, ok := a.(*Template); ok {
- a = t.Name
- } else if q, ok := a.(*Qualified); ok {
- a = q.Name
- } else if t, ok := a.(*TaggedName); ok {
- a = t.Name
- } else {
- return a
- }
- }
- }
-
- isCast := false
- for {
- if len(st.str) == 0 {
- st.fail("expected prefix")
- }
- var next AST
-
- c := st.str[0]
- if isDigit(c) || isLower(c) || c == 'U' || c == 'L' {
- next = st.unqualifiedName()
- if _, ok := next.(*Cast); ok {
- isCast = true
- }
- } else {
- switch st.str[0] {
- case 'C':
- if len(st.str) < 2 {
- st.fail("expected constructor type")
- }
- if last == nil {
- st.fail("constructor before name is seen")
- }
- st.advance(2)
- next = &Constructor{Name: getLast(last)}
- case 'D':
- if len(st.str) > 1 && (st.str[1] == 'T' || st.str[1] == 't') {
- next = st.demangleType(false)
- } else {
- if len(st.str) < 2 {
- st.fail("expected destructor type")
- }
- if last == nil {
- st.fail("destructor before name is seen")
- }
- st.advance(2)
- next = &Destructor{Name: getLast(last)}
- }
- case 'S':
- next = st.substitution(true)
- case 'I':
- if a == nil {
- st.fail("unexpected template arguments")
- }
- var args []AST
- args = st.templateArgs()
- tmpl := &Template{Name: a, Args: args}
- if isCast {
- st.setTemplate(a, tmpl)
- isCast = false
- }
- a = nil
- next = tmpl
- case 'T':
- next = st.templateParam()
- case 'E':
- return a
- case 'M':
- if a == nil {
- st.fail("unexpected lambda initializer")
- }
- // This is the initializer scope for a
- // lambda. We don't need to record
- // it. The normal code will treat the
- // variable has a type scope, which
- // gives appropriate output.
- st.advance(1)
- continue
- default:
- st.fail("unrecognized letter in prefix")
- }
- }
- last = next
- if a == nil {
- a = next
- } else {
- a = &Qualified{Scope: a, Name: next, LocalName: false}
- }
-
- if c != 'S' && (len(st.str) == 0 || st.str[0] != 'E') {
- st.subs.add(a)
- }
- }
- }
-
- // <unqualified-name> ::= <operator-name>
- // ::= <ctor-dtor-name>
- // ::= <source-name>
- // ::= <local-source-name>
- //
- // <local-source-name> ::= L <source-name> <discriminator>
- func (st *state) unqualifiedName() AST {
- if len(st.str) < 1 {
- st.fail("expected unqualified name")
- }
- var a AST
- c := st.str[0]
- if isDigit(c) {
- a = st.sourceName()
- } else if isLower(c) {
- a, _ = st.operatorName(false)
- if op, ok := a.(*Operator); ok && op.Name == `operator"" ` {
- n := st.sourceName()
- a = &Unary{Op: op, Expr: n, Suffix: false, SizeofType: false}
- }
- } else {
- switch c {
- case 'C', 'D':
- st.fail("constructor/destructor not in nested name")
- case 'L':
- st.advance(1)
- a = st.sourceName()
- a = st.discriminator(a)
- case 'U':
- if len(st.str) < 2 {
- st.advance(1)
- st.fail("expected closure or unnamed type")
- }
- c := st.str[1]
- switch c {
- case 'l':
- a = st.closureTypeName()
- case 't':
- a = st.unnamedTypeName()
- default:
- st.advance(1)
- st.fail("expected closure or unnamed type")
- }
- default:
- st.fail("expected unqualified name")
- }
- }
-
- if len(st.str) > 0 && st.str[0] == 'B' {
- a = st.taggedName(a)
- }
-
- return a
- }
-
- // <source-name> ::= <(positive length) number> <identifier>
- // identifier ::= <(unqualified source code identifier)>
- func (st *state) sourceName() AST {
- val := st.number()
- if val < 0 {
- st.fail("unexpected negative number")
- }
- if len(st.str) < val {
- st.fail("not enough characters for identifier")
- }
- id := st.str[:val]
- st.advance(val)
-
- // Look for GCC encoding of anonymous namespace, and make it
- // more friendly.
- const anonPrefix = "_GLOBAL_"
- if strings.HasPrefix(id, anonPrefix) && len(id) > len(anonPrefix)+2 {
- c1 := id[len(anonPrefix)]
- c2 := id[len(anonPrefix)+1]
- if (c1 == '.' || c1 == '_' || c1 == '$') && c2 == 'N' {
- id = "(anonymous namespace)"
- }
- }
-
- n := &Name{Name: id}
- return n
- }
-
- // number ::= [n] <(non-negative decimal integer)>
- func (st *state) number() int {
- neg := false
- if len(st.str) > 0 && st.str[0] == 'n' {
- neg = true
- st.advance(1)
- }
- if len(st.str) == 0 || !isDigit(st.str[0]) {
- st.fail("missing number")
- }
- val := 0
- for len(st.str) > 0 && isDigit(st.str[0]) {
- // Number picked to ensure we can't overflow with 32-bit int.
- // Any very large number here is bogus.
- if val >= 0x80000000/10-10 {
- st.fail("numeric overflow")
- }
- val = val*10 + int(st.str[0]-'0')
- st.advance(1)
- }
- if neg {
- val = -val
- }
- return val
- }
-
- // An operator is the demangled name, and the number of arguments it
- // takes in an expression.
- type operator struct {
- name string
- args int
- }
-
- // The operators map maps the mangled operator names to information
- // about them.
- var operators = map[string]operator{
- "aN": {"&=", 2},
- "aS": {"=", 2},
- "aa": {"&&", 2},
- "ad": {"&", 1},
- "an": {"&", 2},
- "at": {"alignof ", 1},
- "az": {"alignof ", 1},
- "cc": {"const_cast", 2},
- "cl": {"()", 2},
- "cm": {",", 2},
- "co": {"~", 1},
- "dV": {"/=", 2},
- "da": {"delete[] ", 1},
- "dc": {"dynamic_cast", 2},
- "de": {"*", 1},
- "dl": {"delete ", 1},
- "ds": {".*", 2},
- "dt": {".", 2},
- "dv": {"/", 2},
- "eO": {"^=", 2},
- "eo": {"^", 2},
- "eq": {"==", 2},
- "ge": {">=", 2},
- "gs": {"::", 1},
- "gt": {">", 2},
- "ix": {"[]", 2},
- "lS": {"<<=", 2},
- "le": {"<=", 2},
- "li": {`operator"" `, 1},
- "ls": {"<<", 2},
- "lt": {"<", 2},
- "mI": {"-=", 2},
- "mL": {"*=", 2},
- "mi": {"-", 2},
- "ml": {"*", 2},
- "mm": {"--", 1},
- "na": {"new[]", 3},
- "ne": {"!=", 2},
- "ng": {"-", 1},
- "nt": {"!", 1},
- "nw": {"new", 3},
- "oR": {"|=", 2},
- "oo": {"||", 2},
- "or": {"|", 2},
- "pL": {"+=", 2},
- "pl": {"+", 2},
- "pm": {"->*", 2},
- "pp": {"++", 1},
- "ps": {"+", 1},
- "pt": {"->", 2},
- "qu": {"?", 3},
- "rM": {"%=", 2},
- "rS": {">>=", 2},
- "rc": {"reinterpret_cast", 2},
- "rm": {"%", 2},
- "rs": {">>", 2},
- "sc": {"static_cast", 2},
- "st": {"sizeof ", 1},
- "sz": {"sizeof ", 1},
- "tr": {"throw", 0},
- "tw": {"throw ", 1},
- }
-
- // operator_name ::= many different two character encodings.
- // ::= cv <type>
- // ::= v <digit> <source-name>
- //
- // We need to know whether we are in an expression because it affects
- // how we handle template parameters in the type of a cast operator.
- func (st *state) operatorName(inExpression bool) (AST, int) {
- if len(st.str) < 2 {
- st.fail("missing operator code")
- }
- code := st.str[:2]
- st.advance(2)
- if code[0] == 'v' && isDigit(code[1]) {
- name := st.sourceName()
- return &Operator{Name: name.(*Name).Name}, int(code[1] - '0')
- } else if code == "cv" {
- // Push a nil on templates to indicate that template
- // parameters will have their template filled in
- // later.
- if !inExpression {
- st.templates = append(st.templates, nil)
- }
-
- t := st.demangleType(!inExpression)
-
- if !inExpression {
- st.templates = st.templates[:len(st.templates)-1]
- }
-
- return &Cast{To: t}, 1
- } else if op, ok := operators[code]; ok {
- return &Operator{Name: op.name}, op.args
- } else {
- st.failEarlier("unrecognized operator code", 2)
- panic("not reached")
- }
- }
-
- // <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
- // ::= Z <(function) encoding> E s [<discriminator>]
- // ::= Z <(function) encoding> E d [<parameter> number>] _ <entity name>
- func (st *state) localName() AST {
- st.checkChar('Z')
- fn := st.encoding(true)
- if len(st.str) == 0 || st.str[0] != 'E' {
- st.fail("expected E after local name")
- }
- st.advance(1)
- if len(st.str) > 0 && st.str[0] == 's' {
- st.advance(1)
- var n AST = &Name{Name: "string literal"}
- n = st.discriminator(n)
- return &Qualified{Scope: fn, Name: n, LocalName: true}
- } else {
- num := -1
- if len(st.str) > 0 && st.str[0] == 'd' {
- // Default argument scope.
- st.advance(1)
- num = st.compactNumber()
- }
- var n AST = st.name()
- n = st.discriminator(n)
- if num >= 0 {
- n = &DefaultArg{Num: num, Arg: n}
- }
- return &Qualified{Scope: fn, Name: n, LocalName: true}
- }
- }
-
- // Parse a Java resource special-name.
- func (st *state) javaResource() AST {
- off := st.off
- ln := st.number()
- if ln <= 1 {
- st.failEarlier("java resource length less than 1", st.off-off)
- }
- if len(st.str) == 0 || st.str[0] != '_' {
- st.fail("expected _ after number")
- }
- st.advance(1)
- ln--
- if len(st.str) < ln {
- st.fail("not enough characters for java resource length")
- }
- str := st.str[:ln]
- final := ""
- st.advance(ln)
- for i := 0; i < len(str); i++ {
- if str[i] != '$' {
- final += string(str[i])
- } else {
- if len(str) <= i+1 {
- st.failEarlier("java resource escape at end of string", 1)
- }
- i++
- r, ok := map[byte]string{
- 'S': "/",
- '_': ".",
- '$': "$",
- }[str[i]]
- if !ok {
- st.failEarlier("unrecognized java resource escape", ln-i-1)
- }
- final += r
- }
- }
- return &Special{Prefix: "java resource ", Val: &Name{Name: final}}
- }
-
- // <special-name> ::= TV <type>
- // ::= TT <type>
- // ::= TI <type>
- // ::= TS <type>
- // ::= GV <(object) name>
- // ::= T <call-offset> <(base) encoding>
- // ::= Tc <call-offset> <call-offset> <(base) encoding>
- // Also g++ extensions:
- // ::= TC <type> <(offset) number> _ <(base) type>
- // ::= TF <type>
- // ::= TJ <type>
- // ::= GR <name>
- // ::= GA <encoding>
- // ::= Gr <resource name>
- // ::= GTt <encoding>
- // ::= GTn <encoding>
- func (st *state) specialName() AST {
- if st.str[0] == 'T' {
- st.advance(1)
- if len(st.str) == 0 {
- st.fail("expected special name code")
- }
- c := st.str[0]
- st.advance(1)
- switch c {
- case 'V':
- t := st.demangleType(false)
- return &Special{Prefix: "vtable for ", Val: t}
- case 'T':
- t := st.demangleType(false)
- return &Special{Prefix: "VTT for ", Val: t}
- case 'I':
- t := st.demangleType(false)
- return &Special{Prefix: "typeinfo for ", Val: t}
- case 'S':
- t := st.demangleType(false)
- return &Special{Prefix: "typeinfo name for ", Val: t}
- case 'h':
- st.callOffset('h')
- v := st.encoding(true)
- return &Special{Prefix: "non-virtual thunk to ", Val: v}
- case 'v':
- st.callOffset('v')
- v := st.encoding(true)
- return &Special{Prefix: "virtual thunk to ", Val: v}
- case 'c':
- st.callOffset(0)
- st.callOffset(0)
- v := st.encoding(true)
- return &Special{Prefix: "covariant return thunk to ", Val: v}
- case 'C':
- derived := st.demangleType(false)
- off := st.off
- offset := st.number()
- if offset < 0 {
- st.failEarlier("expected positive offset", st.off-off)
- }
- if len(st.str) == 0 || st.str[0] != '_' {
- st.fail("expected _ after number")
- }
- st.advance(1)
- base := st.demangleType(false)
- return &Special2{Prefix: "construction vtable for ", Val1: base, Middle: "-in-", Val2: derived}
- case 'F':
- t := st.demangleType(false)
- return &Special{Prefix: "typeinfo fn for ", Val: t}
- case 'J':
- t := st.demangleType(false)
- return &Special{Prefix: "java Class for ", Val: t}
- case 'H':
- n := st.name()
- return &Special{Prefix: "TLS init function for ", Val: n}
- case 'W':
- n := st.name()
- return &Special{Prefix: "TLS wrapper function for ", Val: n}
- default:
- st.fail("unrecognized special T name code")
- panic("not reached")
- }
- } else {
- st.checkChar('G')
- if len(st.str) == 0 {
- st.fail("expected special name code")
- }
- c := st.str[0]
- st.advance(1)
- switch c {
- case 'V':
- n := st.name()
- return &Special{Prefix: "guard variable for ", Val: n}
- case 'R':
- n := st.name()
- i := st.number()
- return &Special{Prefix: fmt.Sprintf("reference temporary #%d for ", i), Val: n}
- case 'A':
- v := st.encoding(true)
- return &Special{Prefix: "hidden alias for ", Val: v}
- case 'T':
- if len(st.str) == 0 {
- st.fail("expected special GT name code")
- }
- c := st.str[0]
- st.advance(1)
- v := st.encoding(true)
- switch c {
- case 'n':
- return &Special{Prefix: "non-transaction clone for ", Val: v}
- default:
- // The proposal is that different
- // letters stand for different types
- // of transactional cloning. Treat
- // them all the same for now.
- fallthrough
- case 't':
- return &Special{Prefix: "transaction clone for ", Val: v}
- }
- case 'r':
- return st.javaResource()
- default:
- st.fail("unrecognized special G name code")
- panic("not reached")
- }
- }
- }
-
- // <call-offset> ::= h <nv-offset> _
- // ::= v <v-offset> _
- //
- // <nv-offset> ::= <(offset) number>
- //
- // <v-offset> ::= <(offset) number> _ <(virtual offset) number>
- //
- // The c parameter, if not 0, is a character we just read which is the
- // start of the <call-offset>.
- //
- // We don't display the offset information anywhere.
- func (st *state) callOffset(c byte) {
- if c == 0 {
- if len(st.str) == 0 {
- st.fail("missing call offset")
- }
- c = st.str[0]
- st.advance(1)
- }
- switch c {
- case 'h':
- st.number()
- case 'v':
- st.number()
- if len(st.str) == 0 || st.str[0] != '_' {
- st.fail("expected _ after number")
- }
- st.advance(1)
- st.number()
- default:
- st.failEarlier("unrecognized call offset code", 1)
- }
- if len(st.str) == 0 || st.str[0] != '_' {
- st.fail("expected _ after call offset")
- }
- st.advance(1)
- }
-
- // builtinTypes maps the type letter to the type name.
- var builtinTypes = map[byte]string{
- 'a': "signed char",
- 'b': "bool",
- 'c': "char",
- 'd': "double",
- 'e': "long double",
- 'f': "float",
- 'g': "__float128",
- 'h': "unsigned char",
- 'i': "int",
- 'j': "unsigned int",
- 'l': "long",
- 'm': "unsigned long",
- 'n': "__int128",
- 'o': "unsigned __int128",
- 's': "short",
- 't': "unsigned short",
- 'v': "void",
- 'w': "wchar_t",
- 'x': "long long",
- 'y': "unsigned long long",
- 'z': "...",
- }
-
- // <type> ::= <builtin-type>
- // ::= <function-type>
- // ::= <class-enum-type>
- // ::= <array-type>
- // ::= <pointer-to-member-type>
- // ::= <template-param>
- // ::= <template-template-param> <template-args>
- // ::= <substitution>
- // ::= <CV-qualifiers> <type>
- // ::= P <type>
- // ::= R <type>
- // ::= O <type> (C++0x)
- // ::= C <type>
- // ::= G <type>
- // ::= U <source-name> <type>
- //
- // <builtin-type> ::= various one letter codes
- // ::= u <source-name>
- //
- // The isCast parameter is for a rather hideous parse. When we see a
- // tempate-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, we pass in 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) demangleType(isCast bool) AST {
- if len(st.str) == 0 {
- st.fail("expected type")
- }
-
- addSubst := true
-
- q := st.cvQualifiers()
- if len(q) > 0 {
- if len(st.str) == 0 {
- st.fail("expected type")
- }
-
- // CV-qualifiers before a function type apply to
- // 'this', so avoid adding the unqualified function
- // type to the substitution list.
- if st.str[0] == 'F' {
- addSubst = false
- }
- }
-
- var ret AST
-
- // Use correct substitution for a template parameter.
- var sub AST
-
- if btype, ok := builtinTypes[st.str[0]]; ok {
- ret = &BuiltinType{Name: btype}
- st.advance(1)
- if len(q) > 0 {
- ret = &TypeWithQualifiers{Base: ret, Qualifiers: q}
- st.subs.add(ret)
- }
- return ret
- }
- c := st.str[0]
- switch c {
- case 'u':
- st.advance(1)
- ret = st.sourceName()
- case 'F':
- ret = st.functionType()
- case 'N', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- ret = st.name()
- case 'A':
- ret = st.arrayType(isCast)
- case 'M':
- ret = st.pointerToMemberType(isCast)
- case 'T':
- ret = st.templateParam()
- if len(st.str) > 0 && st.str[0] == 'I' {
- // See the function comment to explain this.
- if !isCast {
- st.subs.add(ret)
- args := st.templateArgs()
- ret = &Template{Name: ret, Args: args}
- } else {
- save := st.copy()
-
- var args []AST
- failed := false
- func() {
- defer func() {
- if r := recover(); r != nil {
- if _, ok := r.(demangleErr); ok {
- failed = true
- } else {
- panic(r)
- }
- }
- }()
-
- args = st.templateArgs()
- }()
-
- if !failed && len(st.str) > 0 && st.str[0] == 'I' {
- st.subs.add(ret)
- ret = &Template{Name: ret, Args: args}
- } else {
- // Reset back to before we started
- // reading the template arguments.
- // They will be read again by
- // st.prefix.
- *st = *save
- }
- }
- }
- case 'S':
- // If this is a special substitution, then it
- // is the start of <class-enum-type>.
- var c2 byte
- if len(st.str) > 1 {
- c2 = st.str[1]
- }
- if isDigit(c2) || c2 == '_' || isUpper(c2) {
- ret = st.substitution(false)
- if len(st.str) == 0 || st.str[0] != 'I' {
- addSubst = false
- } else {
- args := st.templateArgs()
- ret = &Template{Name: ret, Args: args}
- }
- } 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':
- st.advance(1)
- n := st.sourceName()
- if len(st.str) > 0 && st.str[0] == 'I' {
- args := st.templateArgs()
- n = &Template{Name: n, Args: args}
- }
- t := st.demangleType(isCast)
- ret = &VendorQualifier{Qualifier: n, Type: t}
- case 'D':
- st.advance(1)
- if len(st.str) == 0 {
- st.fail("expected D code for type")
- }
- addSubst = false
- c2 := st.str[0]
- st.advance(1)
- switch c2 {
- case 'T', 't':
- // decltype(expression)
- ret = st.expression()
- if len(st.str) == 0 || st.str[0] != 'E' {
- st.fail("expected E after expression in type")
- }
- st.advance(1)
- ret = &Decltype{Expr: ret}
- addSubst = true
-
- case 'p':
- t := st.demangleType(isCast)
- pack := st.findArgumentPack(t)
- ret = &PackExpansion{Base: t, Pack: pack}
- addSubst = true
-
- case 'a':
- ret = &Name{Name: "auto"}
-
- case 'f':
- ret = &BuiltinType{Name: "decimal32"}
- case 'd':
- ret = &BuiltinType{Name: "decimal64"}
- case 'e':
- ret = &BuiltinType{Name: "decimal128"}
- case 'h':
- ret = &BuiltinType{Name: "half"}
- case 's':
- ret = &BuiltinType{Name: "char16_t"}
- case 'i':
- ret = &BuiltinType{Name: "char32_t"}
- case 'n':
- ret = &BuiltinType{Name: "decltype(nullptr)"}
-
- case 'F':
- accum := false
- if len(st.str) > 0 && isDigit(st.str[0]) {
- accum = true
- // We don't care about the bits.
- _ = st.number()
- }
- base := st.demangleType(isCast)
- if len(st.str) > 0 && isDigit(st.str[0]) {
- // We don't care about the bits.
- st.number()
- }
- sat := false
- if len(st.str) > 0 {
- if st.str[0] == 's' {
- sat = true
- }
- st.advance(1)
- }
- ret = &FixedType{Base: base, Accum: accum, Sat: sat}
-
- case 'v':
- ret = st.vectorType(isCast)
- addSubst = true
-
- default:
- st.fail("unrecognized D code in type")
- }
-
- default:
- st.fail("unrecognized type code")
- }
-
- if addSubst {
- if sub != nil {
- st.subs.add(sub)
- } else {
- st.subs.add(ret)
- }
- }
-
- if len(q) > 0 {
- if _, ok := ret.(*FunctionType); ok {
- ret = &MethodWithQualifiers{Method: ret, Qualifiers: q, RefQualifier: ""}
- } else if mwq, ok := ret.(*MethodWithQualifiers); ok {
- // Merge adjacent qualifiers. This case
- // happens with a function with a trailing
- // ref-qualifier.
- mwq.Qualifiers = mergeQualifiers(q, mwq.Qualifiers)
- } else {
- // Merge adjacent qualifiers. This case
- // happens with multi-dimensional array types.
- if qsub, ok := ret.(*TypeWithQualifiers); ok {
- q = mergeQualifiers(q, qsub.Qualifiers)
- ret = qsub.Base
- }
- ret = &TypeWithQualifiers{Base: ret, Qualifiers: q}
- }
- st.subs.add(ret)
- }
-
- return ret
- }
-
- // mergeQualifiers merges two qualifer lists into one.
- func mergeQualifiers(q1, q2 Qualifiers) Qualifiers {
- m := make(map[string]bool)
- for _, qual := range q1 {
- m[qual] = true
- }
- for _, qual := range q2 {
- if !m[qual] {
- q1 = append(q1, qual)
- m[qual] = true
- }
- }
- return q1
- }
-
- // qualifiers maps from the character used in the mangled name to the
- // string to print.
- var qualifiers = map[byte]string{
- 'r': "restrict",
- 'V': "volatile",
- 'K': "const",
- }
-
- // <CV-qualifiers> ::= [r] [V] [K]
- func (st *state) cvQualifiers() Qualifiers {
- var q Qualifiers
- for len(st.str) > 0 {
- if qv, ok := qualifiers[st.str[0]]; ok {
- q = append([]string{qv}, q...)
- st.advance(1)
- } else if len(st.str) > 1 && st.str[:2] == "Dx" {
- q = append([]string{"transaction_safe"}, q...)
- st.advance(2)
- } else {
- break
- }
- }
- return q
- }
-
- // <ref-qualifier> ::= R
- // ::= O
- func (st *state) refQualifier() string {
- if len(st.str) > 0 {
- switch st.str[0] {
- case 'R':
- st.advance(1)
- return "&"
- case 'O':
- st.advance(1)
- return "&&"
- }
- }
- return ""
- }
-
- // <type>+
- func (st *state) parmlist() []AST {
- var ret []AST
- for {
- if len(st.str) < 1 {
- break
- }
- if st.str[0] == 'E' || st.str[0] == '.' {
- break
- }
- if (st.str[0] == 'R' || st.str[0] == 'O') && len(st.str) > 1 && st.str[1] == 'E' {
- // This is a function ref-qualifier.
- break
- }
- ptype := st.demangleType(false)
- ret = append(ret, ptype)
- }
-
- // There should always be at least one type. A function that
- // takes no arguments will have a single parameter type
- // "void".
- if len(ret) == 0 {
- st.fail("expected at least one type in type list")
- }
-
- // Omit a single parameter type void.
- if len(ret) == 1 {
- if bt, ok := ret[0].(*BuiltinType); ok && bt.Name == "void" {
- ret = nil
- }
- }
-
- return ret
- }
-
- // <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
- func (st *state) functionType() AST {
- st.checkChar('F')
- if len(st.str) > 0 && st.str[0] == 'Y' {
- // Function has C linkage. We don't print this.
- st.advance(1)
- }
- ret := st.bareFunctionType(true)
- r := st.refQualifier()
- if r != "" {
- ret = &MethodWithQualifiers{Method: ret, Qualifiers: nil, RefQualifier: r}
- }
- if len(st.str) == 0 || st.str[0] != 'E' {
- st.fail("expected E after function type")
- }
- st.advance(1)
- return ret
- }
-
- // <bare-function-type> ::= [J]<type>+
- func (st *state) bareFunctionType(hasReturnType bool) AST {
- if len(st.str) > 0 && st.str[0] == 'J' {
- hasReturnType = true
- st.advance(1)
- }
- var returnType AST
- if hasReturnType {
- returnType = st.demangleType(false)
- }
- types := st.parmlist()
- return &FunctionType{Return: returnType, Args: types}
- }
-
- // <array-type> ::= A <(positive dimension) number> _ <(element) type>
- // ::= A [<(dimension) expression>] _ <(element) type>
- func (st *state) arrayType(isCast bool) AST {
- st.checkChar('A')
-
- if len(st.str) == 0 {
- st.fail("missing array dimension")
- }
-
- var dim AST
- if st.str[0] == '_' {
- dim = &Name{Name: ""}
- } else if isDigit(st.str[0]) {
- i := 1
- for len(st.str) > i && isDigit(st.str[i]) {
- i++
- }
- dim = &Name{Name: st.str[:i]}
- st.advance(i)
- } else {
- dim = st.expression()
- }
-
- if len(st.str) == 0 || st.str[0] != '_' {
- st.fail("expected _ after dimension")
- }
- st.advance(1)
-
- t := st.demangleType(isCast)
-
- arr := &ArrayType{Dimension: dim, Element: t}
-
- // Qualifiers on the element of an array type go on the whole
- // array type.
- if q, ok := arr.Element.(*TypeWithQualifiers); ok {
- return &TypeWithQualifiers{Base: &ArrayType{Dimension: dim, Element: q.Base}, Qualifiers: q.Qualifiers}
- }
-
- return arr
- }
-
- // <vector-type> ::= Dv <number> _ <type>
- // ::= Dv _ <expression> _ <type>
- func (st *state) vectorType(isCast bool) AST {
- if len(st.str) == 0 {
- st.fail("expected vector dimension")
- }
-
- var dim AST
- if st.str[0] == '_' {
- st.advance(1)
- dim = st.expression()
- } else {
- num := st.number()
- dim = &Name{Name: fmt.Sprintf("%d", num)}
- }
-
- if len(st.str) == 0 || st.str[0] != '_' {
- st.fail("expected _ after vector dimension")
- }
- st.advance(1)
-
- t := st.demangleType(isCast)
-
- return &VectorType{Dimension: dim, Base: t}
- }
-
- // <pointer-to-member-type> ::= M <(class) type> <(member) type>
- func (st *state) pointerToMemberType(isCast bool) AST {
- st.checkChar('M')
- cl := st.demangleType(false)
-
- // The ABI says, "The type of a non-static member function is
- // considered to be different, for the purposes of
- // substitution, from the type of a namespace-scope or static
- // member function whose type appears similar. The types of
- // two non-static member functions are considered to be
- // different, for the purposes of substitution, if the
- // functions are members of different classes. In other words,
- // for the purposes of substitution, the class of which the
- // function is a member is considered part of the type of
- // function."
- //
- // For a pointer to member function, this call to demangleType
- // will end up adding a (possibly qualified) non-member
- // function type to the substitution table, which is not
- // correct; however, the member function type will never be
- // used in a substitution, so putting the wrong type in the
- // substitution table is harmless.
- mem := st.demangleType(isCast)
- return &PtrMem{Class: cl, Member: mem}
- }
-
- // <non-negative number> _ */
- func (st *state) compactNumber() int {
- if len(st.str) == 0 {
- st.fail("missing index")
- }
- if st.str[0] == '_' {
- st.advance(1)
- return 0
- } else if st.str[0] == 'n' {
- st.fail("unexpected negative number")
- }
- n := st.number()
- if len(st.str) == 0 || st.str[0] != '_' {
- st.fail("missing underscore after number")
- }
- st.advance(1)
- return n + 1
- }
-
- // <template-param> ::= T_
- // ::= T <(parameter-2 non-negative) number> _
- //
- // When a template parameter is a substitution candidate, any
- // reference to that substitution refers to the template parameter
- // with the same index in the currently active template, not to
- // whatever the template parameter would be expanded to here. We sort
- // this out in substitution and simplify.
- func (st *state) templateParam() AST {
- if len(st.templates) == 0 {
- st.fail("template parameter not in scope of template")
- }
- off := st.off
-
- st.checkChar('T')
- n := st.compactNumber()
-
- template := st.templates[len(st.templates)-1]
-
- if template == nil {
- // We are parsing a cast operator. If the cast is
- // itself a template, then this is a forward
- // reference. Fill it in later.
- return &TemplateParam{Index: n, Template: nil}
- }
-
- if n >= len(template.Args) {
- st.failEarlier(fmt.Sprintf("template index out of range (%d >= %d)", n, len(template.Args)), st.off-off)
- }
-
- return &TemplateParam{Index: n, Template: template}
- }
-
- // setTemplate sets the Template field of any TemplateParam's in a.
- // This handles the forward referencing template parameters found in
- // cast operators.
- func (st *state) setTemplate(a AST, tmpl *Template) {
- a.Traverse(func(a AST) bool {
- switch a := a.(type) {
- case *TemplateParam:
- if a.Template != nil {
- panic("internal error")
- }
- if tmpl == nil {
- st.fail("cast template parameter not in scope of template")
- }
- if a.Index >= len(tmpl.Args) {
- st.fail(fmt.Sprintf("cast template index out of range (%d >= %d)", a.Index, len(tmpl.Args)))
- }
- a.Template = tmpl
- return false
- default:
- return true
- }
- })
- }
-
- // <template-args> ::= I <template-arg>+ E
- func (st *state) templateArgs() []AST {
- if len(st.str) == 0 || (st.str[0] != 'I' && st.str[0] != 'J') {
- panic("internal error")
- }
- st.advance(1)
-
- var ret []AST
- for len(st.str) == 0 || st.str[0] != 'E' {
- arg := st.templateArg()
- ret = append(ret, arg)
- }
- st.advance(1)
- return ret
- }
-
- // <template-arg> ::= <type>
- // ::= X <expression> E
- // ::= <expr-primary>
- func (st *state) templateArg() AST {
- if len(st.str) == 0 {
- st.fail("missing template argument")
- }
- switch st.str[0] {
- case 'X':
- st.advance(1)
- expr := st.expression()
- if len(st.str) == 0 || st.str[0] != 'E' {
- st.fail("missing end of expression")
- }
- st.advance(1)
- return expr
-
- case 'L':
- return st.exprPrimary()
-
- case 'I', 'J':
- args := st.templateArgs()
- return &ArgumentPack{Args: args}
-
- default:
- return st.demangleType(false)
- }
- }
-
- // exprList parses a sequence of expressions up to a terminating character.
- func (st *state) exprList(stop byte) AST {
- if len(st.str) > 0 && st.str[0] == stop {
- st.advance(1)
- return &ExprList{Exprs: nil}
- }
-
- var exprs []AST
- for {
- e := st.expression()
- exprs = append(exprs, e)
- if len(st.str) > 0 && st.str[0] == stop {
- st.advance(1)
- break
- }
- }
- return &ExprList{Exprs: exprs}
- }
-
- // <expression> ::= <(unary) operator-name> <expression>
- // ::= <(binary) operator-name> <expression> <expression>
- // ::= <(trinary) operator-name> <expression> <expression> <expression>
- // ::= cl <expression>+ E
- // ::= st <type>
- // ::= <template-param>
- // ::= sr <type> <unqualified-name>
- // ::= sr <type> <unqualified-name> <template-args>
- // ::= <expr-primary>
- func (st *state) expression() AST {
- if len(st.str) == 0 {
- st.fail("expected expression")
- }
- if st.str[0] == 'L' {
- return st.exprPrimary()
- } else if st.str[0] == 'T' {
- return st.templateParam()
- } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'r' {
- st.advance(2)
- if len(st.str) == 0 {
- st.fail("expected unresolved type")
- }
- switch st.str[0] {
- case 'T', 'D', 'S':
- t := st.demangleType(false)
- n := st.unqualifiedName()
- n = &Qualified{Scope: t, Name: n, LocalName: false}
- if len(st.str) > 0 && st.str[0] == 'I' {
- args := st.templateArgs()
- n = &Template{Name: n, Args: args}
- }
- return n
- default:
- var s AST
- if st.str[0] == 'N' {
- st.advance(1)
- s = st.demangleType(false)
- }
- for len(st.str) == 0 || st.str[0] != 'E' {
- // GCC does not seem to follow the ABI here.
- // It can emit type/name without an 'E'.
- if s != nil && len(st.str) > 0 && !isDigit(st.str[0]) {
- if q, ok := s.(*Qualified); ok {
- a := q.Scope
- if t, ok := a.(*Template); ok {
- st.subs.add(t.Name)
- st.subs.add(t)
- } else {
- st.subs.add(a)
- }
- return s
- }
- }
- n := st.sourceName()
- if len(st.str) > 0 && st.str[0] == 'I' {
- args := st.templateArgs()
- n = &Template{Name: n, Args: args}
- }
- if s == nil {
- s = n
- } else {
- s = &Qualified{Scope: s, Name: n, LocalName: false}
- }
- }
- if s == nil {
- st.fail("missing scope in unresolved name")
- }
- st.advance(1)
- // TODO(iant): Handle "on" and "dn".
- n := st.sourceName()
- if len(st.str) > 0 && st.str[0] == 'I' {
- args := st.templateArgs()
- n = &Template{Name: n, Args: args}
- }
- return &Qualified{Scope: s, Name: n, LocalName: false}
- }
- } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'p' {
- st.advance(2)
- e := st.expression()
- pack := st.findArgumentPack(e)
- return &PackExpansion{Base: e, Pack: pack}
- } else if st.str[0] == 'f' && len(st.str) > 1 && st.str[1] == 'p' {
- st.advance(2)
- if len(st.str) > 0 && st.str[0] == 'T' {
- st.advance(1)
- return &FunctionParam{Index: 0}
- } else {
- index := st.compactNumber()
- return &FunctionParam{Index: index + 1}
- }
- } else if isDigit(st.str[0]) || (st.str[0] == 'o' && len(st.str) > 1 && st.str[1] == 'n') {
- if st.str[0] == 'o' {
- // Skip operator function ID.
- st.advance(2)
- }
- n := st.unqualifiedName()
- if len(st.str) > 0 && st.str[0] == 'I' {
- args := st.templateArgs()
- n = &Template{Name: n, Args: args}
- }
- return n
- } else if (st.str[0] == 'i' || st.str[0] == 't') && len(st.str) > 1 && st.str[1] == 'l' {
- // Brace-enclosed initializer list.
- c := st.str[0]
- st.advance(2)
- var t AST
- if c == 't' {
- t = st.demangleType(false)
- }
- exprs := st.exprList('E')
- return &InitializerList{Type: t, Exprs: exprs}
- } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 't' {
- o, _ := st.operatorName(true)
- t := st.demangleType(false)
- return &Unary{Op: o, Expr: t, Suffix: false, SizeofType: true}
- } else {
- if len(st.str) < 2 {
- st.fail("missing operator code")
- }
- code := st.str[:2]
- o, args := st.operatorName(true)
- switch args {
- case 0:
- return &Nullary{Op: o}
-
- case 1:
- suffix := false
- if code == "pp" || code == "mm" {
- if len(st.str) > 0 && st.str[0] == '_' {
- st.advance(1)
- } else {
- suffix = true
- }
- }
- var operand AST
- if _, ok := o.(*Cast); ok && len(st.str) > 0 && st.str[0] == '_' {
- st.advance(1)
- operand = st.exprList('E')
- } else {
- operand = st.expression()
- }
- return &Unary{Op: o, Expr: operand, Suffix: suffix, SizeofType: false}
-
- case 2:
- var left, right AST
- if code == "sc" || code == "dc" || code == "cc" || code == "rc" {
- left = st.demangleType(false)
- } else {
- left = st.expression()
- }
- if code == "cl" {
- right = st.exprList('E')
- } else if code == "dt" || code == "pt" {
- right = st.unqualifiedName()
- if len(st.str) > 0 && st.str[0] == 'I' {
- args := st.templateArgs()
- right = &Template{Name: right, Args: args}
- }
- } else {
- right = st.expression()
- }
- return &Binary{Op: o, Left: left, Right: right}
-
- case 3:
- if code[0] == 'n' {
- if code[1] != 'w' && code[1] != 'a' {
- panic("internal error")
- }
- place := st.exprList('_')
- if place.(*ExprList).Exprs == nil {
- place = nil
- }
- t := st.demangleType(false)
- var ini AST
- if len(st.str) > 0 && st.str[0] == 'E' {
- st.advance(1)
- } else if len(st.str) > 1 && st.str[0] == 'p' && st.str[1] == 'i' {
- // Parenthesized initializer.
- st.advance(2)
- ini = st.exprList('E')
- } else if len(st.str) > 1 && st.str[0] == 'i' && st.str[1] == 'l' {
- // Initializer list.
- ini = st.expression()
- } else {
- st.fail("unrecognized new initializer")
- }
- return &New{Op: o, Place: place, Type: t, Init: ini}
- } else {
- first := st.expression()
- second := st.expression()
- third := st.expression()
- return &Trinary{Op: o, First: first, Second: second, Third: third}
- }
-
- default:
- st.fail(fmt.Sprintf("unsupported number of operator arguments: %d", args))
- panic("not reached")
- }
- }
- }
-
- // <expr-primary> ::= L <type> <(value) number> E
- // ::= L <type> <(value) float> E
- // ::= L <mangled-name> E
- func (st *state) exprPrimary() AST {
- st.checkChar('L')
- if len(st.str) == 0 {
- st.fail("expected primary expression")
-
- }
-
- // Check for 'Z' here because g++ incorrectly omitted the
- // underscore until -fabi-version=3.
- var ret AST
- if st.str[0] == '_' || st.str[0] == 'Z' {
- if st.str[0] == '_' {
- st.advance(1)
- }
- if len(st.str) == 0 || st.str[0] != 'Z' {
- st.fail("expected mangled name")
- }
- st.advance(1)
- ret = st.encoding(true)
- } else {
- t := st.demangleType(false)
-
- neg := false
- if len(st.str) > 0 && st.str[0] == 'n' {
- neg = true
- st.advance(1)
- }
- i := 0
- for len(st.str) > 0 && st.str[i] != 'E' {
- i++
- }
- val := st.str[:i]
- st.advance(i)
- ret = &Literal{Type: t, Val: val, Neg: neg}
- }
- if len(st.str) == 0 || st.str[0] != 'E' {
- st.fail("expected E after literal")
- }
- st.advance(1)
- return ret
- }
-
- // <discriminator> ::= _ <(non-negative) number>
- func (st *state) discriminator(a AST) AST {
- if len(st.str) == 0 || st.str[0] != '_' {
- return a
- }
- off := st.off
- st.advance(1)
- d := st.number()
- if d < 0 {
- st.failEarlier("invalid negative discriminator", st.off-off)
- }
- // We don't currently print out the discriminator, so we don't
- // save it.
- return a
- }
-
- // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
- func (st *state) closureTypeName() AST {
- st.checkChar('U')
- st.checkChar('l')
- types := st.parmlist()
- if len(st.str) == 0 || st.str[0] != 'E' {
- st.fail("expected E after closure type name")
- }
- st.advance(1)
- num := st.compactNumber()
- ret := &Closure{Types: types, Num: num}
- st.subs.add(ret)
- return ret
- }
-
- // <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
- func (st *state) unnamedTypeName() AST {
- st.checkChar('U')
- st.checkChar('t')
- num := st.compactNumber()
- ret := &UnnamedType{Num: num}
- st.subs.add(ret)
- return ret
- }
-
- // Recognize a clone suffix. These are not part of the mangling API,
- // but are added by GCC when cloning functions.
- func (st *state) cloneSuffix(a AST) AST {
- i := 0
- if len(st.str) > 1 && st.str[0] == '.' && (isLower(st.str[1]) || st.str[1] == '_') {
- i += 2
- for len(st.str) > i && (isLower(st.str[i]) || st.str[i] == '_') {
- i++
- }
- }
- for len(st.str) > i+1 && st.str[i] == '.' && isDigit(st.str[i+1]) {
- i += 2
- for len(st.str) > i && isDigit(st.str[i]) {
- i++
- }
- }
- suffix := st.str[:i]
- st.advance(i)
- return &Clone{Base: a, Suffix: suffix}
- }
-
- // substitutions is the list of substitution candidates that may
- // appear later in the string.
- type substitutions []AST
-
- // add adds a new substitution candidate.
- func (subs *substitutions) add(a AST) {
- *subs = append(*subs, a)
- }
-
- // subAST maps standard substitution codes to the corresponding AST.
- var subAST = map[byte]AST{
- 't': &Name{Name: "std"},
- 'a': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}},
- 'b': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}},
- 's': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "string"}},
- 'i': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "istream"}},
- 'o': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "ostream"}},
- 'd': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "iostream"}},
- }
-
- // verboseAST maps standard substitution codes to the long form of the
- // corresponding AST. We use this when the Verbose option is used, to
- // match the standard demangler.
- var verboseAST = map[byte]AST{
- 't': &Name{Name: "std"},
- 'a': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}},
- 'b': &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}},
-
- // std::basic_string<char, std::char_traits<char>, std::allocator<char> >
- 's': &Template{
- Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_string"}},
- Args: []AST{
- &BuiltinType{Name: "char"},
- &Template{
- Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
- Args: []AST{&BuiltinType{Name: "char"}}},
- &Template{
- Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "allocator"}},
- Args: []AST{&BuiltinType{Name: "char"}}}}},
- // std::basic_istream<char, std::char_traits<char> >
- 'i': &Template{
- Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_istream"}},
- Args: []AST{
- &BuiltinType{Name: "char"},
- &Template{
- Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
- Args: []AST{&BuiltinType{Name: "char"}}}}},
- // std::basic_ostream<char, std::char_traits<char> >
- 'o': &Template{
- Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_ostream"}},
- Args: []AST{
- &BuiltinType{Name: "char"},
- &Template{
- Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
- Args: []AST{&BuiltinType{Name: "char"}}}}},
- // std::basic_iostream<char, std::char_traits<char> >
- 'd': &Template{
- Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "basic_iostream"}},
- Args: []AST{
- &BuiltinType{Name: "char"},
- &Template{
- Name: &Qualified{Scope: &Name{Name: "std"}, Name: &Name{Name: "char_traits"}},
- Args: []AST{&BuiltinType{Name: "char"}}}}},
- }
-
- // <substitution> ::= S <seq-id> _
- // ::= S_
- // ::= St
- // ::= Sa
- // ::= Sb
- // ::= Ss
- // ::= Si
- // ::= So
- // ::= Sd
- func (st *state) substitution(forPrefix bool) AST {
- st.checkChar('S')
- if len(st.str) == 0 {
- st.fail("missing substitution index")
- }
- c := st.str[0]
- st.advance(1)
- dec := 1
- if c == '_' || isDigit(c) || isUpper(c) {
- id := 0
- if c != '_' {
- for c != '_' {
- // Don't overflow a 32-bit int.
- if id >= 0x80000000/36-36 {
- st.fail("substitution index overflow")
- }
- if isDigit(c) {
- id = id*36 + int(c-'0')
- } else if isUpper(c) {
- id = id*36 + int(c-'A') + 10
- } else {
- st.fail("invalid character in substitution index")
- }
-
- if len(st.str) == 0 {
- st.fail("missing end to substitution index")
- }
- c = st.str[0]
- st.advance(1)
- dec++
- }
- id++
- }
-
- if id >= len(st.subs) {
- st.failEarlier(fmt.Sprintf("substitution index out of range (%d >= %d)", id, len(st.subs)), dec)
- }
-
- ret := st.subs[id]
-
- // We need to update any references to template
- // parameters to refer to the currently active
- // template.
- copy := func(a AST) AST {
- tp, ok := a.(*TemplateParam)
- if !ok {
- return nil
- }
- if len(st.templates) == 0 {
- st.failEarlier("substituted template parameter not in scope of template", dec)
- }
- template := st.templates[len(st.templates)-1]
- if template == nil {
- // This template parameter is within
- // the scope of a cast operator.
- return &TemplateParam{Index: tp.Index, Template: nil}
- }
-
- if tp.Index >= len(template.Args) {
- st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", tp.Index, len(template.Args)), dec)
- }
-
- return &TemplateParam{Index: tp.Index, Template: template}
- }
- skip := func(a AST) bool {
- if _, ok := a.(*Typed); ok {
- return true
- }
- return false
- }
- if c := ret.Copy(copy, skip); c != nil {
- return c
- }
-
- return ret
- } else {
- m := subAST
- if st.verbose {
- m = verboseAST
- }
- // For compatibility with the standard demangler, use
- // a longer name for a constructor or destructor.
- if forPrefix && len(st.str) > 0 && (st.str[0] == 'C' || st.str[0] == 'D') {
- m = verboseAST
- }
- a, ok := m[c]
- if !ok {
- st.failEarlier("unrecognized substitution code", 1)
- }
-
- if len(st.str) > 0 && st.str[0] == 'B' {
- a = st.taggedName(a)
- }
-
- return a
- }
- }
-
- // isDigit returns whetner c is a digit for demangling purposes.
- func isDigit(c byte) bool {
- return c >= '0' && c <= '9'
- }
-
- // isUpper returns whether c is an upper case letter for demangling purposes.
- func isUpper(c byte) bool {
- return c >= 'A' && c <= 'Z'
- }
-
- // isLower returns whether c is a lower case letter for demangling purposes.
- func isLower(c byte) bool {
- return c >= 'a' && c <= 'z'
- }
-
- // simplify replaces template parameters with their expansions, and
- // merges qualifiers.
- func simplify(a AST) AST {
- skip := func(a AST) bool {
- return false
- }
- if r := a.Copy(simplifyOne, skip); r != nil {
- return r
- }
- return a
- }
-
- // simplifyOne simplifies a single AST. It returns nil if there is
- // nothing to do.
- func simplifyOne(a AST) AST {
- switch a := a.(type) {
- case *TemplateParam:
- if a.Template == nil || a.Index >= len(a.Template.Args) {
- panic("internal error")
- }
- return a.Template.Args[a.Index]
- case *MethodWithQualifiers:
- if m, ok := a.Method.(*MethodWithQualifiers); ok {
- ref := a.RefQualifier
- if ref == "" {
- ref = m.RefQualifier
- } else if m.RefQualifier != "" {
- if ref == "&" || m.RefQualifier == "&" {
- ref = "&"
- }
- }
- return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: ref}
- }
- if t, ok := a.Method.(*TypeWithQualifiers); ok {
- return &MethodWithQualifiers{Method: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers), RefQualifier: a.RefQualifier}
- }
- case *TypeWithQualifiers:
- if ft, ok := a.Base.(*FunctionType); ok {
- return &MethodWithQualifiers{Method: ft, Qualifiers: a.Qualifiers, RefQualifier: ""}
- }
- if t, ok := a.Base.(*TypeWithQualifiers); ok {
- return &TypeWithQualifiers{Base: t.Base, Qualifiers: mergeQualifiers(a.Qualifiers, t.Qualifiers)}
- }
- if m, ok := a.Base.(*MethodWithQualifiers); ok {
- return &MethodWithQualifiers{Method: m.Method, Qualifiers: mergeQualifiers(a.Qualifiers, m.Qualifiers), RefQualifier: m.RefQualifier}
- }
- case *ReferenceType:
- if rt, ok := a.Base.(*ReferenceType); ok {
- return rt
- }
- if rrt, ok := a.Base.(*RvalueReferenceType); ok {
- return &ReferenceType{Base: rrt.Base}
- }
- case *RvalueReferenceType:
- if rrt, ok := a.Base.(*RvalueReferenceType); ok {
- return rrt
- }
- if rt, ok := a.Base.(*ReferenceType); ok {
- return rt
- }
- case *ArrayType:
- // Qualifiers on the element of an array type
- // go on the whole array type.
- if q, ok := a.Element.(*TypeWithQualifiers); ok {
- return &TypeWithQualifiers{
- Base: &ArrayType{Dimension: a.Dimension, Element: q.Base},
- Qualifiers: q.Qualifiers,
- }
- }
- case *PackExpansion:
- // Expand the pack and replace it with a list of
- // expressions.
- if a.Pack != nil {
- exprs := make([]AST, len(a.Pack.Args))
- for i, arg := range a.Pack.Args {
- copy := func(sub AST) AST {
- // Replace the ArgumentPack
- // with a specific argument.
- if sub == a.Pack {
- return arg
- }
- // Copy everything else.
- return nil
- }
-
- skip := func(sub AST) bool {
- // Don't traverse into another
- // pack expansion.
- _, skip := sub.(*PackExpansion)
- return skip
- }
-
- exprs[i] = simplify(a.Base.Copy(copy, skip))
- }
- return &ExprList{Exprs: exprs}
- }
- }
- return nil
- }
-
- // findArgumentPack walks the AST looking for the argument pack for a
- // pack expansion. We find it via a template parameter.
- func (st *state) findArgumentPack(a AST) *ArgumentPack {
- var ret *ArgumentPack
- a.Traverse(func(a AST) bool {
- if ret != nil {
- return false
- }
- switch a := a.(type) {
- case *TemplateParam:
- if a.Template == nil || a.Index >= len(a.Template.Args) {
- return true
- }
- if pack, ok := a.Template.Args[a.Index].(*ArgumentPack); ok {
- ret = pack
- return false
- }
- case *PackExpansion, *Closure, *Name:
- return false
- case *TaggedName, *Operator, *BuiltinType, *FunctionParam:
- return false
- case *UnnamedType, *FixedType, *DefaultArg:
- return false
- }
- return true
- })
- return ret
- }
|