@@ -1029,6 +1029,21 @@ string DemangleGNU3::DemanglePrimaryExpression()
10291029 dedent ()
10301030 return out;
10311031 }
1032+ // LZ<encoding>E: function address template arg (GCC/Clang, without leading underscore)
1033+ if (m_reader.Peek () == ' Z' )
1034+ {
1035+ m_reader.Consume (); // 'Z'
1036+ auto savedTemplateSubstitute2 = m_templateSubstitute;
1037+ m_templateSubstitute.clear ();
1038+ oldTopLevel = m_topLevel;
1039+ m_topLevel = true ;
1040+ DemangledTypeNode t2 = DemangleSymbol (tmpList);
1041+ m_topLevel = oldTopLevel;
1042+ m_templateSubstitute = std::move (savedTemplateSubstitute2);
1043+ out += t2.GetTypeAndName (tmpList);
1044+ dedent ();
1045+ return out;
1046+ }
10321047 switch (m_reader.Read ())
10331048 {
10341049 case ' b' :
@@ -1584,13 +1599,23 @@ string DemangleGNU3::DemangleExpression()
15841599 case hash (' p' ,' p' ): // ++ (postfix in <expression> context)
15851600 case hash (' m' ,' m' ): // -- (postfix in <expression> context)
15861601 return DemangleUnarySuffixExpression (GetOperator (elm1, elm2));
1602+ case hash (' d' ,' t' ): // .
1603+ {
1604+ const string dtObj = DemangleExpression ();
1605+ const string dtMem = DemangleExpression ();
1606+ return dtObj + " ." + dtMem;
1607+ }
1608+ case hash (' p' ,' t' ): // ->
1609+ {
1610+ const string ptObj = DemangleExpression ();
1611+ const string ptMem = DemangleExpression ();
1612+ return ptObj + " ->" + ptMem;
1613+ }
15871614 case hash (' l' ,' s' ): // <<
15881615 case hash (' r' ,' s' ): // >>
15891616 case hash (' a' ,' S' ): // =
15901617 case hash (' e' ,' q' ): // ==
15911618 case hash (' n' ,' e' ): // !=
1592- case hash (' d' ,' t' ): // .
1593- case hash (' p' ,' t' ): // ->
15941619 case hash (' m' ,' l' ): // *
15951620 case hash (' m' ,' i' ): // -
15961621 case hash (' p' ,' l' ): // +
@@ -1629,7 +1654,23 @@ string DemangleGNU3::DemangleExpression()
16291654 DemangleExpression () + " :" +
16301655 DemangleExpression ();
16311656 case hash (' c' ,' l' ): // ()
1632- return " (" + DemangleExpressionList () + " )" ;
1657+ {
1658+ const string callable = DemangleExpression ();
1659+ string args;
1660+ bool firstArg = true ;
1661+ m_functionSubstitute.push_back ({});
1662+ while (m_reader.Peek () != ' E' )
1663+ {
1664+ if (!firstArg) args += " , " ;
1665+ const string e = DemangleExpression ();
1666+ args += e;
1667+ m_functionSubstitute.back ().push_back (CreateUnknownType (e));
1668+ firstArg = false ;
1669+ }
1670+ m_functionSubstitute.pop_back ();
1671+ m_reader.Consume (); // 'E'
1672+ return callable + " (" + args + " )" ;
1673+ }
16331674 case hash (' c' ,' v' ): // type (expression)
16341675 {
16351676 DemangledTypeNode type = DemangleType ();
@@ -1660,11 +1701,11 @@ string DemangleGNU3::DemangleExpression()
16601701 int64_t listNumber = 0 ;
16611702 int64_t elementNum = 0 ;
16621703 char elm;
1663- if (m_functionSubstitute.size () == 0 )
1664- throw DemangleException ();
1665-
16661704 if (elm2 == ' L' )
16671705 {
1706+ // fL case requires a valid function substitute frame
1707+ if (m_functionSubstitute.size () == 0 )
1708+ throw DemangleException ();
16681709 listNumber = DemangleNumber () + 1 ;
16691710 if (listNumber < 0 ||
16701711 (uint64_t )listNumber >= (uint64_t )m_functionSubstitute.size () ||
@@ -1676,20 +1717,27 @@ string DemangleGNU3::DemangleExpression()
16761717 if (elm == ' _' )
16771718 {
16781719 m_reader.Consume (1 );
1679- if ((size_t )elementNum >= m_functionSubstitute[listNumber].size ())
1720+ if ((uint64_t )listNumber >= (uint64_t )m_functionSubstitute.size () ||
1721+ (size_t )elementNum >= m_functionSubstitute[listNumber].size ())
16801722 {
1681- throw DemangleException ();
1723+ // fp_ used before params are known (e.g., in decltype return type)
1724+ out = (elementNum == 0 ) ? " fp" : " fp" + std::to_string (elementNum - 1 );
1725+ break ;
16821726 }
16831727 type = m_functionSubstitute[listNumber][elementNum];
16841728 }
16851729 else if (isdigit (elm) || isupper (elm))
16861730 {
16871731 elementNum = DemangleNumber () + 1 ;
1688- if (m_reader.Read () != ' _' ||
1689- elementNum < 0 ||
1732+ if (m_reader.Read () != ' _' )
1733+ throw DemangleException ();
1734+ if (elementNum < 0 ||
1735+ (uint64_t )listNumber >= (uint64_t )m_functionSubstitute.size () ||
16901736 (size_t )elementNum >= m_functionSubstitute[listNumber].size ())
16911737 {
1692- throw DemangleException ();
1738+ // fpN_ used before params are known
1739+ out = " fp" + std::to_string (elementNum - 1 );
1740+ break ;
16931741 }
16941742 type = m_functionSubstitute[listNumber][elementNum];
16951743 }
@@ -2246,8 +2294,26 @@ DemangledTypeNode DemangleGNU3::DemangleSymbol(QualifiedName& varName)
22462294 // Guard variable encoding starts with: N (nested), L (local), S (substitution), digit, etc.
22472295 char peekChar = m_reader.Peek ();
22482296 bool isVectorABI = (peekChar == ' b' || peekChar == ' c' || peekChar == ' d' || peekChar == ' e' ||
2249- peekChar == ' x' || peekChar == ' y' || peekChar == ' Y' ||
2250- peekChar == ' z' || peekChar == ' Z' );
2297+ peekChar == ' x' || peekChar == ' y' || peekChar == ' Y' );
2298+ // 'z'/'Z' are ambiguous: also used as Z-local-name prefix in guard variables
2299+ // (e.g. _ZGVZN1A1BEvE1A = guard variable for A::B()::A).
2300+ // Disambiguate by verifying the Vector ABI pattern: <isa><mask(M|N)><vlen(digits)><vparam or _>.
2301+ if (!isVectorABI && (peekChar == ' z' || peekChar == ' Z' ))
2302+ {
2303+ _STD_STRING ahead = m_reader.PeekString (8 );
2304+ if (ahead.size () >= 3 && (ahead[1 ] == ' M' || ahead[1 ] == ' N' ))
2305+ {
2306+ size_t pos = 2 ;
2307+ while (pos < ahead.size () && isdigit ((unsigned char )ahead[pos]))
2308+ pos++;
2309+ if (pos > 2 )
2310+ {
2311+ char after = (pos < ahead.size ()) ? ahead[pos] : ' \0 ' ;
2312+ isVectorABI = (after == ' _' || after == ' v' || after == ' l' ||
2313+ after == ' u' || after == ' R' || after == ' L' );
2314+ }
2315+ }
2316+ }
22512317 if (!isVectorABI)
22522318 {
22532319 // Guard variable (original behavior)
0 commit comments