Skip to content

Commit cf394aa

Browse files
committed
Fix LZ function-pointer template args, cl/dt expression formatting, fp_ in decltype
- DemanglePrimaryExpression: handle LZ<encoding>E (function address without leading underscore, used by GCC/Clang for pointer-to-function non-type template args). e.g. __ZNK1aI1bIP1cELZN1a1e1fEvELZNS5_1fEEE1iEv -> a<b<c*>, a::e::f(), a::e::f>::i() const - fp_/fp<N>_ in decltype return types: return placeholder name ("fp", "fp0", etc.) instead of throwing when m_functionSubstitute is empty or too small (params not yet parsed at the time the return type DT expression is evaluated). - cl expression: format as callable(args) instead of (callable, args). - dt/pt expressions: remove unnecessary parens around operands; use obj.member and obj->member format directly for clean output. e.g. _ZN1a1bIN1c1dINS0_1eEEEE1fIKS3_EEDTcldtfp_1gEERT_i -> fp.g() a::b<c::d<a::b::e>>::f<a::b::e const>(a::b::e const&, int32_t)
1 parent cfa2f00 commit cf394aa

1 file changed

Lines changed: 79 additions & 13 deletions

File tree

demangler/gnu3/demangle_gnu3.cpp

Lines changed: 79 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)