@@ -30,7 +30,7 @@ using namespace std;
3030#endif
3131
3232
33- #define MAX_DEMANGLE_LENGTH 4096
33+ #define MAX_DEMANGLE_LENGTH 262144
3434#define hash (x,y ) (64 * x + y)
3535
3636#undef GNUDEMANGLE_DEBUG
@@ -308,7 +308,8 @@ DemangleGNU3::DemangleGNU3(Architecture* arch, const string& mangledName) :
308308 m_isParameter(false ),
309309 m_shouldDeleteReader(true ),
310310 m_topLevel(true ),
311- m_isOperatorOverload(false )
311+ m_isOperatorOverload(false ),
312+ m_permitForwardTemplateRefs(false )
312313{
313314 MyLogDebug (" %s : %s\n " , __FUNCTION__, m_reader.GetRaw ().c_str ());
314315}
@@ -330,6 +331,9 @@ void DemangleGNU3::Reset(Architecture* arch, const string& mangledName)
330331 m_shouldDeleteReader = true ;
331332 m_topLevel = true ;
332333 m_isOperatorOverload = false ;
334+ m_permitForwardTemplateRefs = false ;
335+ m_pendingForwardRefs.clear ();
336+ m_inLocalName = false ;
333337}
334338
335339
@@ -369,10 +373,7 @@ void DemangleGNU3::PushTemplateType(const DemangledTypeNode& type)
369373const DemangledTypeNode& DemangleGNU3::GetTemplateType (size_t ref)
370374{
371375 if (ref >= m_templateSubstitute.size ())
372- {
373- // PrintTables();
374376 throw DemangleException ();
375- }
376377 return m_templateSubstitute[ref];
377378}
378379
@@ -386,10 +387,7 @@ void DemangleGNU3::PushType(const DemangledTypeNode& type)
386387const DemangledTypeNode& DemangleGNU3::GetType (size_t ref)
387388{
388389 if (ref >= m_substitute.size ())
389- {
390- // PrintTables();
391390 throw DemangleException ();
392- }
393391 return m_substitute[ref];
394392}
395393
@@ -482,7 +480,43 @@ DemangledTypeNode DemangleGNU3::DemangleFunction(bool cnst, bool vltl)
482480}
483481
484482
485- const DemangledTypeNode& DemangleGNU3::DemangleTemplateSubstitution ()
483+ string DemangleGNU3::ForwardRefPlaceholder (size_t index)
484+ {
485+ return " \x01F WDREF:" + to_string (index) + " \x01 " ;
486+ }
487+
488+
489+ void DemangleGNU3::ResolveForwardTemplateRefs (DemangledTypeNode& type, const vector<string>& args)
490+ {
491+ if (m_pendingForwardRefs.empty ())
492+ return ;
493+ auto & segs = type.GetMutableTypeName ();
494+ bool resolved = false ;
495+ for (const auto & fr : m_pendingForwardRefs)
496+ {
497+ string placeholder = ForwardRefPlaceholder (fr.index );
498+ string replacement = (fr.index < args.size ()) ? args[fr.index ] : " auto" ;
499+ for (auto & seg : segs)
500+ {
501+ size_t pos;
502+ while ((pos = seg.find (placeholder)) != string::npos)
503+ {
504+ seg.replace (pos, placeholder.size (), replacement);
505+ resolved = true ;
506+ }
507+ }
508+ }
509+ // Only clear the pending list when we actually resolved something. Inner
510+ // nested-name 'I' handlers (e.g. template args of types nested inside the
511+ // cv-operator result type) may call here with a type that does not contain
512+ // the placeholder; we must not discard the pending entry in that case so
513+ // that the correct outer 'I' handler can still resolve it.
514+ if (resolved)
515+ m_pendingForwardRefs.clear ();
516+ }
517+
518+
519+ DemangledTypeNode DemangleGNU3::DemangleTemplateSubstitution ()
486520{
487521 indent ();
488522 MyLogDebug (" %s : %s\n " , __FUNCTION__, m_reader.GetRaw ().c_str ());
@@ -512,7 +546,20 @@ const DemangledTypeNode& DemangleGNU3::DemangleTemplateSubstitution()
512546 throw DemangleException ();
513547 }
514548 dedent ();
515- return GetTemplateType (number);
549+
550+ if (number < m_templateSubstitute.size ())
551+ return m_templateSubstitute[number];
552+
553+ // If forward template references are permitted (e.g. inside a cv conversion
554+ // operator type), return a placeholder that will be resolved once the outer
555+ // template args are known.
556+ if (m_permitForwardTemplateRefs)
557+ {
558+ m_pendingForwardRefs.push_back ({number});
559+ return CreateUnknownType (ForwardRefPlaceholder (number));
560+ }
561+
562+ throw DemangleException ();
516563}
517564
518565
@@ -615,8 +662,11 @@ DemangledTypeNode DemangleGNU3::DemangleType()
615662
616663 // Template Substitution
617664 type = DemangleTemplateSubstitution ();
618- substitute = true ;
619- if (m_reader.Peek () == ' I' )
665+ // In forward-ref mode (cv conversion operator type parsing), do not consume
666+ // trailing I<args>E — it belongs to the enclosing nested-name and will be
667+ // processed by DemangleNestedName's 'I' case, which resolves forward refs.
668+ substitute = !m_permitForwardTemplateRefs;
669+ if (!m_permitForwardTemplateRefs && m_reader.Peek () == ' I' )
620670 {
621671 m_reader.Consume ();
622672 if (substitute)
@@ -884,7 +934,11 @@ DemangledTypeNode DemangleGNU3::DemangleSubstitution()
884934 }
885935
886936 dedent ();
887- return GetType (number);
937+ const DemangledTypeNode& resolved = GetType (number);
938+ const auto & segs = resolved.GetTypeName ();
939+ if (!segs.empty ())
940+ m_lastName = segs.back ();
941+ return resolved;
888942 }
889943 m_lastName = name.back ();
890944 dedent ();
@@ -1273,8 +1327,22 @@ DemangledTypeNode DemangleGNU3::DemangleUnqualifiedName()
12731327 break ;
12741328 }
12751329 case hash (' c' ,' v' ): // type (expression)
1276- outType = CreateUnknownType (" operator " + DemangleType ().GetString ());
1330+ {
1331+ // The conversion operator type may reference template params (T_, T0_, ...)
1332+ // that aren't yet in m_templateSubstitute (they're defined by a following
1333+ // I<args>E in the enclosing nested name). Set m_permitForwardTemplateRefs so
1334+ // that DemangleTemplateSubstitution() returns a placeholder instead of
1335+ // throwing, and don't consume trailing I<args>E in the T case of DemangleType.
1336+ // The outer DemangleNestedName case 'I' will parse those args and call
1337+ // ResolveForwardTemplateRefs() to patch the placeholders.
1338+ bool savedPermit = m_permitForwardTemplateRefs;
1339+ m_pendingForwardRefs.clear ();
1340+ m_permitForwardTemplateRefs = true ;
1341+ DemangledTypeNode cvType = DemangleType ();
1342+ m_permitForwardTemplateRefs = savedPermit;
1343+ outType = CreateUnknownType (" operator " + cvType.GetString ());
12771344 break ;
1345+ }
12781346 default :
12791347 m_reader.UnRead (2 );
12801348 if (isdigit (m_reader.Peek ()) || m_reader.Read () == ' L' )
@@ -1368,10 +1436,21 @@ DemangledTypeNode DemangleGNU3::DemangleUnresolvedType()
13681436 type.SetHasTemplateArguments (true );
13691437 PushType (type);
13701438 }
1439+ else
1440+ {
1441+ // Template param used as scope qualifier (e.g. sr T_ name) is a substitution
1442+ // candidate: the compiler adds it to the main sub table so subsequent
1443+ // occurrences can use Sn_ instead of T_.
1444+ PushType (type);
1445+ }
13711446 }
13721447 else if (m_reader.Length () > 2 && (m_reader.PeekString (2 ) == " Dt" || m_reader.PeekString (2 ) == " DT" ))
13731448 {
1449+ m_reader.Consume (); // 'D'
1450+ m_reader.Consume (); // 't' or 'T'
13741451 const string name = " decltype(" + DemangleExpression () + " )" ;
1452+ if (m_reader.Read () != ' E' )
1453+ throw DemangleException ();
13751454 type = CreateUnknownType (name);
13761455 }
13771456 else if (m_reader.Peek () == ' S' )
@@ -1731,7 +1810,7 @@ string DemangleGNU3::DemangleExpression()
17311810}
17321811
17331812
1734- void DemangleGNU3::DemangleTemplateArgs (vector<string>& args)
1813+ void DemangleGNU3::DemangleTemplateArgs (vector<string>& args, bool * hadNonTypeArg )
17351814{
17361815 indent ();
17371816 MyLogDebug (" %s:: '%s'\n " , __FUNCTION__, m_reader.GetRaw ().c_str ());
@@ -1749,16 +1828,23 @@ void DemangleGNU3::DemangleTemplateArgs(vector<string>& args)
17491828 args.push_back (expr);
17501829 tmp = CreateUnknownType (expr);
17511830 tmpValid = true ;
1831+ if (hadNonTypeArg) *hadNonTypeArg = true ;
17521832 break ;
17531833 case ' X' :
17541834 args.push_back (DemangleExpression ());
17551835 if (m_reader.Read () != ' E' )
17561836 throw DemangleException ();
1837+ if (hadNonTypeArg) *hadNonTypeArg = true ;
17571838 break ;
17581839 case ' I' : // GCC sometimes uses I...E for argument packs instead of J...E
17591840 case ' J' :
1841+ {
1842+ size_t prevTemplateSize = m_templateSubstitute.size ();
17601843 DemangleTemplateArgs (args);
1844+ if (m_topLevel && m_templateSubstitute.size () == prevTemplateSize)
1845+ PushTemplateType (CreateUnknownType (" auto" ));
17611846 break ;
1847+ }
17621848 default :
17631849 m_reader.UnRead ();
17641850 topLevel = m_topLevel;
@@ -1781,7 +1867,7 @@ void DemangleGNU3::DemangleTemplateArgs(vector<string>& args)
17811867}
17821868
17831869
1784- DemangledTypeNode DemangleGNU3::DemangleNestedName ()
1870+ DemangledTypeNode DemangleGNU3::DemangleNestedName (bool * allTypeTemplateArgs )
17851871{
17861872 /*
17871873 This can be either a qualified name like: "foo::bar::bas"
@@ -1858,7 +1944,16 @@ DemangledTypeNode DemangleGNU3::DemangleNestedName()
18581944 if (!base)
18591945 throw DemangleException ();
18601946 vector<string> args;
1861- DemangleTemplateArgs (args);
1947+ bool hadNonType = false ;
1948+ DemangleTemplateArgs (args, allTypeTemplateArgs ? &hadNonType : nullptr );
1949+ if (allTypeTemplateArgs)
1950+ *allTypeTemplateArgs = !hadNonType;
1951+ // Resolve any forward template refs created while parsing a cv
1952+ // conversion operator type (e.g. cv T_ where T_ wasn't yet known).
1953+ // Only do this in the outer context (not while still inside the cv
1954+ // type parsing itself where m_permitForwardTemplateRefs is true).
1955+ if (!m_permitForwardTemplateRefs)
1956+ ResolveForwardTemplateRefs (type, args);
18621957 ExtendTypeName (type, GetTemplateString (args));
18631958 type.SetHasTemplateArguments (true );
18641959 isTemplate = true ;
@@ -1948,7 +2043,10 @@ DemangledTypeNode DemangleGNU3::DemangleLocalName()
19482043 m_templateSubstitute.clear ();
19492044 bool oldTopLevel = m_topLevel;
19502045 m_topLevel = true ;
2046+ bool savedInLocalName = m_inLocalName;
2047+ m_inLocalName = true ;
19512048 type = DemangleSymbol (varName);
2049+ m_inLocalName = savedInLocalName;
19522050 m_topLevel = oldTopLevel;
19532051 m_templateSubstitute = std::move (savedTemplateSubstitute);
19542052
@@ -1959,6 +2057,15 @@ DemangledTypeNode DemangleGNU3::DemangleLocalName()
19592057
19602058 if (m_reader.Peek () != ' s' )
19612059 {
2060+ // Handle default argument context: d [<number>] _ <name>
2061+ if (m_reader.Peek () == ' d' )
2062+ {
2063+ m_reader.Consume ();
2064+ if (isdigit (m_reader.Peek ()))
2065+ DemangleNumber ();
2066+ if (m_reader.Peek () == ' _' )
2067+ m_reader.Consume ();
2068+ }
19622069 // <entity name>
19632070 DemangledTypeNode tmpType = DemangleName ();
19642071 type = DemangledTypeNode::NamedType (UnknownNamedTypeClass, varName);
@@ -2049,8 +2156,13 @@ DemangledTypeNode DemangleGNU3::DemangleName()
20492156 }
20502157 break ;
20512158 case ' N' : // <nested-name>
2052- type = DemangleNestedName ();
2159+ {
2160+ bool allTypeArgs = false ;
2161+ type = DemangleNestedName (&allTypeArgs);
2162+ if (!m_inLocalName && allTypeArgs)
2163+ PushType (type);
20532164 break ;
2165+ }
20542166 case ' Z' : // <local-name>
20552167 type = DemangleLocalName ();
20562168 break ;
0 commit comments