Skip to content

Commit 56e1ae6

Browse files
committed
GNU3 demangler: fix sr substitutions, CI2 constructors, M prefix, Z guard disambiguation
- sr unresolved-qualifier-level: remove incorrect PushType calls (expressions don't generate substitution candidates per the Itanium ABI); fix the trailing E to be conditional rather than unconditional to handle GCC's occasional omission when the last qualifier had template-args whose closing E served double duty - Add CI1/CI2 inheriting constructor support in DemangleUnqualifiedName; save and restore m_lastName around DemangleType() to prevent the inherited class type from clobbering the enclosing class name - Handle 'M' data-member-prefix in DemangleNestedName (closure/lambda inside a data member initializer; the M is consumed and the outer name is retained) - Improve guard variable vs Vector ABI disambiguation for z/Z suffixes by scanning all vparam chars ({v,l,u,R,L,s,digits}) and requiring a trailing underscore, preventing false positive vector matches on guard variables
1 parent cf394aa commit 56e1ae6

1 file changed

Lines changed: 45 additions & 19 deletions

File tree

demangler/gnu3/demangle_gnu3.cpp

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,19 @@ DemangledTypeNode DemangleGNU3::DemangleUnqualifiedName()
12671267
outType = CreateUnknownType(m_lastName);
12681268
outType.SetNameType(ConstructorNameType);
12691269
break;
1270+
case hash('C','I'): // Inheriting constructor: CI1 <type> or CI2 <type>
1271+
{
1272+
char kind = m_reader.Read(); // '1' or '2'
1273+
if (kind != '1' && kind != '2')
1274+
throw DemangleException();
1275+
// Save m_lastName: parsing the inherited-class type will overwrite it
1276+
string savedLastName = m_lastName;
1277+
DemangleType();
1278+
m_lastName = savedLastName;
1279+
outType = CreateUnknownType(m_lastName);
1280+
outType.SetNameType(ConstructorNameType);
1281+
break;
1282+
}
12701283
case hash('D','0'): //Destructor
12711284
case hash('D','1'):
12721285
case hash('D','2'):
@@ -1804,33 +1817,25 @@ string DemangleGNU3::DemangleExpression()
18041817
// - the template instantiation (name + args) as another candidate
18051818
// This mirrors how the compiler builds the substitution table during encoding.
18061819
bool hadTemplateArgs = false;
1807-
string accumulated; // full path built so far (for sub table entries)
18081820
do
18091821
{
18101822
hadTemplateArgs = false;
18111823
const string segName = DemangleSourceName();
1812-
accumulated += (accumulated.empty() ? segName : "::" + segName);
1813-
// Push the bare name as a substitution candidate (e.g. "QMetaTypeId2")
1814-
PushType(CreateUnknownType(accumulated));
18151824
out += segName;
18161825
if (m_reader.Peek() == 'I')
18171826
{
18181827
vector<string> args;
18191828
m_reader.Consume();
18201829
DemangleTemplateArgs(args); // consumes the trailing 'E'
1821-
const string tmplStr = GetTemplateString(args);
1822-
accumulated += tmplStr;
1823-
// Push the template instantiation (e.g. "QMetaTypeId2<T>") as a
1824-
// substitution candidate so that later SX_ refs resolve correctly.
1825-
PushType(CreateUnknownType(accumulated));
1826-
out += tmplStr;
1830+
out += GetTemplateString(args);
18271831
hadTemplateArgs = true;
18281832
}
18291833
out += "::";
18301834
}while (!hadTemplateArgs && m_reader.Peek() != 'E');
1831-
// Consume the qualifier-list 'E' only if it wasn't already consumed
1832-
// as the template-args terminator.
1833-
if (!hadTemplateArgs)
1835+
// Consume qualifier-list 'E' if present. GCC sometimes omits it when
1836+
// the last qualifier had template-args whose 'E' served double duty,
1837+
// so check rather than unconditionally consuming.
1838+
if (m_reader.Peek() == 'E')
18341839
m_reader.Consume();
18351840
out += DemangleBaseUnresolvedName().GetString();
18361841
return out;
@@ -1980,6 +1985,10 @@ DemangledTypeNode DemangleGNU3::DemangleNestedName(bool* allTypeTemplateArgs)
19801985
size_t startSize = m_templateSubstitute.size();
19811986
switch (m_reader.Read())
19821987
{
1988+
case 'M': // <data-member-prefix>: closure/lambda inside a data member initializer
1989+
// 'M' follows the member name and marks that subsequent components are
1990+
// scoped inside that data member. Just consume it; the name is already captured.
1991+
continue;
19831992
case 'S': //<substitution>
19841993
newType = DemangleSubstitution();
19851994
substitute = false;
@@ -2297,20 +2306,37 @@ DemangledTypeNode DemangleGNU3::DemangleSymbol(QualifiedName& varName)
22972306
peekChar == 'x' || peekChar == 'y' || peekChar == 'Y');
22982307
// 'z'/'Z' are ambiguous: also used as Z-local-name prefix in guard variables
22992308
// (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 _>.
2309+
// Disambiguate by verifying the full Vector ABI parameter pattern:
2310+
// <isa><mask(M|N)><vlen(digits)><vparams><'_'> where vparams are only
2311+
// from {v, l, u, R, L, s, 0-9} and are immediately followed by '_'.
2312+
// A guard variable's inner symbol would have source-name chars (e.g. 'm', 'a', etc.)
2313+
// that don't appear in valid vparameter sequences.
23012314
if (!isVectorABI && (peekChar == 'z' || peekChar == 'Z'))
23022315
{
2303-
_STD_STRING ahead = m_reader.PeekString(8);
2316+
_STD_STRING ahead = m_reader.PeekString(32);
23042317
if (ahead.size() >= 3 && (ahead[1] == 'M' || ahead[1] == 'N'))
23052318
{
23062319
size_t pos = 2;
23072320
while (pos < ahead.size() && isdigit((unsigned char)ahead[pos]))
23082321
pos++;
2309-
if (pos > 2)
2322+
if (pos > 2) // had at least one vlen digit
23102323
{
2311-
char after = (pos < ahead.size()) ? ahead[pos] : '\0';
2312-
isVectorABI = (after == '_' || after == 'v' || after == 'l' ||
2313-
after == 'u' || after == 'R' || after == 'L');
2324+
// Scan through vparameter chars; valid ones are v/l/u/R/L and
2325+
// optional stride digits/'s'. Anything else means guard variable.
2326+
bool allVparam = true;
2327+
while (pos < ahead.size() && ahead[pos] != '_')
2328+
{
2329+
char c = ahead[pos];
2330+
if (c == 'v' || c == 'l' || c == 'u' || c == 'R' ||
2331+
c == 'L' || c == 's' || isdigit((unsigned char)c))
2332+
pos++;
2333+
else
2334+
{
2335+
allVparam = false;
2336+
break;
2337+
}
2338+
}
2339+
isVectorABI = allVparam && pos < ahead.size() && ahead[pos] == '_';
23142340
}
23152341
}
23162342
}

0 commit comments

Comments
 (0)