// Represents a list of parameters (template params or function arguments.
// It's represented as a linked list.
struct ParamList {
+ bool IsVariadic = false;
+
Type *Current = nullptr;
ParamList *Next = nullptr;
// Write a function or template parameter list.
static void outputParameterList(OutputStream &OS, const ParamList &Params) {
+ if (!Params.Current) {
+ OS << "void";
+ return;
+ }
+
const ParamList *Head = &Params;
while (Head) {
Type::outputPre(OS, *Head->Current);
OS << "static ";
}
- if (ReturnType)
+ if (ReturnType) {
Type::outputPre(OS, *ReturnType);
+ OS << " ";
+ }
outputCallingConvention(OS, CallConvention);
}
OS << " const";
if (Quals & Q_Volatile)
OS << " volatile";
+
+ if (ReturnType)
+ Type::outputPost(OS, *ReturnType);
return;
}
UdtType *demangleClassType();
PointerType *demanglePointerType();
MemberPointerType *demangleMemberPointerType();
+ FunctionType *demangleFunctionType(bool HasThisQuals);
ArrayType *demangleArrayType();
Name *demangleName();
void demangleOperator(Name *);
StringView demangleOperatorName();
- int demangleFunctionClass();
+ FuncClass demangleFunctionClass();
CallingConv demangleCallingConvention();
StorageClass demangleVariableStorageClass();
ReferenceKind demangleReferenceKind();
+ void demangleThrowSpecification();
std::pair<Qualifiers, bool> demangleQualifiers();
// Class template.
Node.Str = demangleString(false);
Node.TemplateParams = demangleParameterList();
- if (!MangledName.consumeFront('@')) {
- Error = true;
- return;
- }
} else if (!IsHead && MangledName.consumeFront("?A")) {
// Anonymous namespace starts with ?A. So does overloaded operator[],
// but the distinguishing factor is that namespace themselves are not
return "";
}
-int Demangler::demangleFunctionClass() {
+FuncClass Demangler::demangleFunctionClass() {
SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
RestoreOnError.shouldRestore(false);
case 'A':
return Private;
case 'B':
- return Private | Far;
+ return FuncClass(Private | Far);
case 'C':
- return Private | Static;
+ return FuncClass(Private | Static);
case 'D':
- return Private | Static;
+ return FuncClass(Private | Static);
case 'E':
- return Private | Virtual;
+ return FuncClass(Private | Virtual);
case 'F':
- return Private | Virtual;
+ return FuncClass(Private | Virtual);
case 'I':
return Protected;
case 'J':
- return Protected | Far;
+ return FuncClass(Protected | Far);
case 'K':
- return Protected | Static;
+ return FuncClass(Protected | Static);
case 'L':
- return Protected | Static | Far;
+ return FuncClass(Protected | Static | Far);
case 'M':
- return Protected | Virtual;
+ return FuncClass(Protected | Virtual);
case 'N':
- return Protected | Virtual | Far;
+ return FuncClass(Protected | Virtual | Far);
case 'Q':
return Public;
case 'R':
- return Public | Far;
+ return FuncClass(Public | Far);
case 'S':
- return Public | Static;
+ return FuncClass(Public | Static);
case 'T':
- return Public | Static | Far;
+ return FuncClass(Public | Static | Far);
case 'U':
- return Public | Virtual;
+ return FuncClass(Public | Virtual);
case 'V':
- return Public | Virtual | Far;
+ return FuncClass(Public | Virtual | Far);
case 'Y':
return Global;
case 'Z':
- return Global | Far;
+ return FuncClass(Global | Far);
}
Error = true;
RestoreOnError.shouldRestore(true);
- return 0;
+ return Public;
}
CallingConv Demangler::demangleCallingConvention() {
return Ty;
}
-static bool functionHasThisPtr(const FunctionType &Ty) {
- assert(Ty.Prim == PrimTy::Function);
- if (Ty.FunctionClass & Global)
- return false;
- if (Ty.FunctionClass & Static)
- return false;
- return true;
-}
-
ReferenceKind Demangler::demangleReferenceKind() {
if (MangledName.consumeFront('G'))
return ReferenceKind::LValueRef;
return ReferenceKind::None;
}
-Type *Demangler::demangleFunctionEncoding() {
- FunctionType *FTy = Arena.alloc<FunctionType>();
+void Demangler::demangleThrowSpecification() {
+ if (MangledName.consumeFront('Z'))
+ return;
+ Error = true;
+}
+
+FunctionType *Demangler::demangleFunctionType(bool HasThisQuals) {
+ FunctionType *FTy = Arena.alloc<FunctionType>();
FTy->Prim = PrimTy::Function;
- FTy->FunctionClass = (FuncClass)demangleFunctionClass();
- if (functionHasThisPtr(*FTy)) {
+
+ if (HasThisQuals) {
FTy->Quals = demanglePointerExtQualifiers();
FTy->RefKind = demangleReferenceKind();
FTy->Quals = Qualifiers(FTy->Quals | demangleQualifiers().first);
FTy->Params = demangleParameterList();
+ demangleThrowSpecification();
+
+ return FTy;
+}
+
+Type *Demangler::demangleFunctionEncoding() {
+ FuncClass FC = demangleFunctionClass();
+
+ bool HasThisQuals = !(FC & (Global | Static));
+ FunctionType *FTy = demangleFunctionType(HasThisQuals);
+ FTy->FunctionClass = FC;
+
return FTy;
}
Qualifiers ExtQuals = demanglePointerExtQualifiers();
Pointer->Quals = Qualifiers(Pointer->Quals | ExtQuals);
- Qualifiers PointeeQuals = Q_None;
- bool IsMember = false;
- std::tie(PointeeQuals, IsMember) = demangleQualifiers();
- assert(IsMember);
- Pointer->MemberName = demangleName();
+ if (MangledName.consumeFront("8")) {
+ Pointer->MemberName = demangleName();
+ Pointer->Pointee = demangleFunctionType(true);
+ } else {
+ Qualifiers PointeeQuals = Q_None;
+ bool IsMember = false;
+ std::tie(PointeeQuals, IsMember) = demangleQualifiers();
+ assert(IsMember);
+ Pointer->MemberName = demangleName();
+
+ Pointer->Pointee = demangleType(QualifierMangleMode::Drop);
+ Pointer->Pointee->Quals = PointeeQuals;
+ }
- Pointer->Pointee = demangleType(QualifierMangleMode::Drop);
- Pointer->Pointee->Quals = PointeeQuals;
return Pointer;
}
Type *BackRef[10];
int Idx = 0;
+ // Empty parameter list.
+ // FIXME: Will this cause problems if demangleParameterList() is called in the
+ // context of a template parameter list?
+ if (MangledName.consumeFront('X'))
+ return {};
+
ParamList *Head;
ParamList **Current = &Head;
while (!Error && !MangledName.startsWith('@') &&
Current = &(*Current)->Next;
}
- return *Head;
+ if (Error)
+ return {};
+
+ // A non-empty parameter list is terminated by either 'Z' (variadic) parameter
+ // list or '@' (non variadic). Careful not to consume "@Z", as in that case
+ // the following Z could be a throw specifier.
+ if (MangledName.consumeFront('@'))
+ return *Head;
+
+ if (MangledName.consumeFront('Z')) {
+ Head->IsVariadic = true;
+ return *Head;
+ }
+
+ Error = true;
+ return {};
}
void Demangler::output() {
StringView dropFront(size_t N = 1) const {
if (N >= size())
- N = size() - 1;
+ N = size();
return StringView(First + N, Last);
}
??4klass@@QEAAAEBV0@AEBV0@@Z
-; CHECK: class klass const &__cdecl klass::operator=(class klass const &)
+; CHECK: class klass const & __cdecl klass::operator=(class klass const &)
??7klass@@QEAA_NXZ
; CHECK: bool __cdecl klass::operator!(void)
; CHECK: int __cdecl klass::operator^=(int)
??6@YAAEBVklass@@AEBV0@H@Z
-; CHECK: class klass const &__cdecl operator<<(class klass const &, int)
+; CHECK: class klass const & __cdecl operator<<(class klass const &, int)
??5@YAAEBVklass@@AEBV0@_K@Z
-; CHECK: class klass const &__cdecl operator>>(class klass const &, unsigned __int64)
+; CHECK: class klass const & __cdecl operator>>(class klass const &, unsigned __int64)
??2@YAPEAX_KAEAVklass@@@Z
-; CHECK: void *__cdecl operator new(unsigned __int64, class klass &)
+; CHECK: void * __cdecl operator new(unsigned __int64, class klass &)
??_U@YAPEAX_KAEAVklass@@@Z
-; CHECK: void *__cdecl operator new[](unsigned __int64, class klass &)
+; CHECK: void * __cdecl operator new[](unsigned __int64, class klass &)
??3@YAXPEAXAEAVklass@@@Z
; CHECK: void __cdecl operator delete(void *, class klass &)
; CHECK: int __cdecl foo::operator+(int)
?static_method@foo@@SAPAV1@XZ
-; CHECK: static class foo *__cdecl foo::static_method(void)
+; CHECK: static class foo * __cdecl foo::static_method(void)
?static_method@foo@@SAPEAV1@XZ
-; CHECK: static class foo *__cdecl foo::static_method(void)
+; CHECK: static class foo * __cdecl foo::static_method(void)
?g@bar@@2HA
; CHECK: static int bar::g
?j@@3P6GHCE@ZA
; CHECK: int __stdcall (*j)(signed char, unsigned char)
+?funptr@@YAP6AHXZXZ
+; CHECK: int __cdecl (* __cdecl funptr(void))(void)
+
?k@@3PTfoo@@DT1@
; CHECK: char const volatile foo::*k
?k@@3PETfoo@@DET1@
; CHECK: char const volatile foo::*k
-; FIXME: We don't support member function pointers yet.
-; ?l@@3P8foo@@AEHH@ZQ1@
-; FIXME: int __thiscall (foo::*l)(int)
+?l@@3P8foo@@AEHH@ZQ1@
+; CHECK: int __thiscall (foo::*l)(int)
?g_cInt@@3HB
; CHECK: int const g_cInt
; CHECK: void __cdecl zeta(int __cdecl (*)(int, int))
??2@YAPAXI@Z
-; CHECK: void *__cdecl operator new(unsigned int)
+; CHECK: void * __cdecl operator new(unsigned int)
??3@YAXPAX@Z
; CHECK: void __cdecl operator delete(void *)
??_U@YAPAXI@Z
-; CHECK: void *__cdecl operator new[](unsigned int)
+; CHECK: void * __cdecl operator new[](unsigned int)
??_V@YAXPAX@Z
; CHECK: void __cdecl operator delete[](void *)
; ?color4@@3QAY02$$CBNA
; FIXME-EXTRACONST: double const (*color4)[3]
-; FIXME-MEMBERPTR: We don't support member pointers yet.
-; ?memptr1@@3RESB@@HES1
-; FIXME-MEMBERPTR: volatile int B::*memptr2
+?memptr1@@3RESB@@HES1@
+; CHECK: int volatile B::*volatile memptr1
-; ?memptr2@@3PESB@@HES1
-; FIXME: volatile int B::*memptr2
+?memptr2@@3PESB@@HES1@
+; CHECK: int volatile B::*memptr2
-; ?memptr3@@3REQB@@HEQ1
-; FIXME-MEMBERPTR: int B::* volatile memptr3
+?memptr3@@3REQB@@HEQ1@
+; CHECK: int B::*volatile memptr3
-; ?funmemptr1@@3RESB@@R6AHXZES1
-; FIXME-MEMBERPTR: int __cdecl (* volatile B::* volatile funmemptr1)(void)
+?funmemptr1@@3RESB@@R6AHXZES1@
+; CHECK: int __cdecl (*volatile B::*volatile funmemptr1)(void)
-; ?funmemptr2@@3PESB@@R6AHXZES1
-; FIXME-MEMBERPTR: int __cdecl (* volatile B::*funmemptr2)(void)
+?funmemptr2@@3PESB@@R6AHXZES1@
+; CHECK: int __cdecl (*volatile B::*funmemptr2)(void)
-; ?funmemptr3@@3REQB@@P6AHXZEQ1
-; FIXME-MEMBERPTR: int __cdecl (* B::*volatile funmemptr3)(void)
+?funmemptr3@@3REQB@@P6AHXZEQ1@
+; CHECK: int __cdecl (*B::*volatile funmemptr3)(void)
-; ?memptrtofun1@@3R8B@@EAAXXZEQ1
-; FIXME-MEMBERPTR: void __cdecl (B::*volatile memptrtofun1)(void)
+?memptrtofun1@@3R8B@@EAAXXZEQ1@
+; CHECK: void __cdecl (B::*volatile memptrtofun1)(void)
-; ?memptrtofun2@@3P8B@@EAAXXZEQ1
-; FIXME-MEMBERPTR: void __cdecl (B::*memptrtofun2)(void)
+?memptrtofun2@@3P8B@@EAAXXZEQ1@
+; CHECK: void __cdecl (B::*memptrtofun2)(void)
-; ?memptrtofun3@@3P8B@@EAAXXZEQ1
-; FIXME-MEMBERPTR: void __cdecl (B::*memptrtofun3)(void)
+?memptrtofun3@@3P8B@@EAAXXZEQ1@
+; CHECK: void __cdecl (B::*memptrtofun3)(void)
-; ?memptrtofun4@@3R8B@@EAAHXZEQ1
-; FIXME-MEMBERPTR: int __cdecl (B::* volatile memptrtofun4)(void)
+?memptrtofun4@@3R8B@@EAAHXZEQ1@
+; CHECK: int __cdecl (B::*volatile memptrtofun4)(void)
-; ?memptrtofun5@@3P8B@@EAA?CHXZEQ1
-; FIXME-MEMBERPTR: int volatile __cdecl (B::*memptrtofun5)(void)
+?memptrtofun5@@3P8B@@EAA?CHXZEQ1@
+; CHECK: int volatile __cdecl (B::*memptrtofun5)(void)
-; ?memptrtofun6@@3P8B@@EAA?BHXZEQ1
-; FIXME-MEMBERPTR: int const __cdecl (B::*memptrtofun6)(void)
+?memptrtofun6@@3P8B@@EAA?BHXZEQ1@
+; CHECK: int const __cdecl (B::*memptrtofun6)(void)
-; ?memptrtofun7@@3R8B@@EAAP6AHXZXZEQ1
-; FIXME-MEMBERPTR: int __cdecl (*(__cdecl B::*volatile memptrtofun7)(void))(void)
+?memptrtofun7@@3R8B@@EAAP6AHXZXZEQ1@
+; CHECK: int __cdecl (* __cdecl (B::*volatile memptrtofun7)(void))(void)
-; ?memptrtofun8@@3P8B@@EAAR6AHXZXZEQ1
-; FIXME-MEMBERPTR: int __cdecl (*(__cdecl B::*memptrtofun8)(void))(void)
+?memptrtofun8@@3P8B@@EAAR6AHXZXZEQ1@
+; CHECK: int __cdecl (*volatile __cdecl (B::*memptrtofun8)(void))(void)
-; ?memptrtofun9@@3P8B@@EAAQ6AHXZXZEQ1
-; FIXME-MEMBERPTR: int __cdecl(*(__cdecl B::*memptrtofun9)(void))(void)
+?memptrtofun9@@3P8B@@EAAQ6AHXZXZEQ1@
+; CHECK: int __cdecl (*const __cdecl (B::*memptrtofun9)(void))(void)
?fooE@@YA?AW4E@@XZ
; FIXME-EXTERNC: int `extern_c_func'::`2'::local
??2OverloadedNewDelete@@SAPAXI@Z
-; CHECK: static void *__cdecl OverloadedNewDelete::operator new(unsigned int)
+; CHECK: static void * __cdecl OverloadedNewDelete::operator new(unsigned int)
??_UOverloadedNewDelete@@SAPAXI@Z
-; CHECK: static void *__cdecl OverloadedNewDelete::operator new[](unsigned int)
+; CHECK: static void * __cdecl OverloadedNewDelete::operator new[](unsigned int)
??3OverloadedNewDelete@@SAXPAX@Z
; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void *)
; CHECK: int __thiscall OverloadedNewDelete::operator+(int)
??2OverloadedNewDelete@@SAPEAX_K@Z
-; CHECK: static void *__cdecl OverloadedNewDelete::operator new(unsigned __int64)
+; CHECK: static void * __cdecl OverloadedNewDelete::operator new(unsigned __int64)
??_UOverloadedNewDelete@@SAPEAX_K@Z
-; CHECK: static void *__cdecl OverloadedNewDelete::operator new[](unsigned __int64)
+; CHECK: static void * __cdecl OverloadedNewDelete::operator new[](unsigned __int64)
??3OverloadedNewDelete@@SAXPEAX@Z
; CHECK: static void __cdecl OverloadedNewDelete::operator delete(void *)
??2TypedefNewDelete@@SAPAXI@Z
-; CHECK: static void *__cdecl TypedefNewDelete::operator new(unsigned int)
+; CHECK: static void * __cdecl TypedefNewDelete::operator new(unsigned int)
??_UTypedefNewDelete@@SAPAXI@Z
-; CHECK: static void *__cdecl TypedefNewDelete::operator new[](unsigned int)
+; CHECK: static void * __cdecl TypedefNewDelete::operator new[](unsigned int)
??3TypedefNewDelete@@SAXPAX@Z
; CHECK: static void __cdecl TypedefNewDelete::operator delete(void *)