ArrayType *demangleArrayType();
- ParamList demangleParameterList();
+ ParamList demangleTemplateParameterList();
+ ParamList demangleFunctionParameterList();
int demangleNumber();
void demangleNamePiece(Name &Node, bool IsHead);
// Memory allocator.
ArenaAllocator Arena;
+ // A single type uses one global back-ref table for all function params.
+ // This means back-refs can even go "into" other types. Examples:
+ //
+ // // Second int* is a back-ref to first.
+ // void foo(int *, int*);
+ //
+ // // Second int* is not a back-ref to first (first is not a function param).
+ // int* foo(int*);
+ //
+ // // Second int* is a back-ref to first (ALL function types share the same
+ // // back-ref map.
+ // using F = void(*)(int*);
+ // F G(int *);
+ Type *FunctionParamBackRefs[10];
+ size_t FunctionParamBackRefCount = 0;
+
// The first 10 BackReferences in a mangled name can be back-referenced by
// special name @[0-9]. This is a storage for the first 10 BackReferences.
StringView BackReferences[10];
} else if (MangledName.consumeFront("?$")) {
// Class template.
Node.Str = demangleString(false);
- Node.TemplateParams = demangleParameterList();
+ Node.TemplateParams = demangleTemplateParameterList();
} 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
if (!IsStructor)
FTy->ReturnType = demangleType(QualifierMangleMode::Result);
- FTy->Params = demangleParameterList();
+ FTy->Params = demangleFunctionParameterList();
demangleThrowSpecification();
}
// Reads a function or a template parameters.
-ParamList Demangler::demangleParameterList() {
- // Within the same parameter list, you can backreference the first 10 types.
- Type *BackRef[10];
- int Idx = 0;
-
+ParamList Demangler::demangleFunctionParameterList() {
// 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 **Current = &Head;
while (!Error && !MangledName.startsWith('@') &&
!MangledName.startsWith('Z')) {
+
if (startsWithDigit(MangledName)) {
int N = MangledName[0] - '0';
- if (N >= Idx) {
+ if (N >= FunctionParamBackRefCount) {
Error = true;
return {};
}
MangledName = MangledName.dropFront();
*Current = Arena.alloc<ParamList>();
- (*Current)->Current = BackRef[N]->clone(Arena);
+ (*Current)->Current = FunctionParamBackRefs[N]->clone(Arena);
Current = &(*Current)->Next;
continue;
}
- size_t ArrayDimension = MangledName.size();
+ size_t OldSize = MangledName.size();
*Current = Arena.alloc<ParamList>();
(*Current)->Current = demangleType(QualifierMangleMode::Drop);
- // Single-letter types are ignored for backreferences because
- // memorizing them doesn't save anything.
- if (Idx <= 9 && ArrayDimension - MangledName.size() > 1)
- BackRef[Idx++] = (*Current)->Current;
+ size_t CharsConsumed = OldSize - MangledName.size();
+ assert(CharsConsumed != 0);
+
+ // Single-letter types are ignored for backreferences because memorizing
+ // them doesn't save anything.
+ if (FunctionParamBackRefCount <= 9 && CharsConsumed > 1)
+ FunctionParamBackRefs[FunctionParamBackRefCount++] = (*Current)->Current;
+
Current = &(*Current)->Next;
}
return {};
}
+ParamList Demangler::demangleTemplateParameterList() {
+ ParamList *Head;
+ ParamList **Current = &Head;
+ while (!Error && !MangledName.startsWith('@')) {
+
+ // Template parameter lists don't participate in back-referencing.
+ *Current = Arena.alloc<ParamList>();
+ (*Current)->Current = demangleType(QualifierMangleMode::Drop);
+
+ Current = &(*Current)->Next;
+ }
+
+ if (Error)
+ return {};
+
+ // Template parameter lists cannot be variadic, so it can only be terminated
+ // by @.
+ if (MangledName.consumeFront('@'))
+ return *Head;
+ Error = true;
+ return {};
+}
+
void Demangler::output() {
// Converts an AST to a string.
//
--- /dev/null
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+?f1@@YAXPBD0@Z
+; CHECK: void __cdecl f1(char const *, char const *)
+
+?f2@@YAXPBDPAD@Z
+; CHECK: void __cdecl f2(char const *, char *)
+
+?f3@@YAXHPBD0@Z
+; CHECK: void __cdecl f3(int, char const *, char const *)
+
+?f4@@YAPBDPBD0@Z
+; CHECK: char const * __cdecl f4(char const *, char const *)
+
+?f5@@YAXPBDIDPBX0I@Z
+; CHECK: void __cdecl f5(char const *, unsigned int, char, void const *, char const *, unsigned int)
+
+?f6@@YAX_N0@Z
+; CHECK: void __cdecl f6(bool, bool)
+
+?f7@@YAXHPAHH0_N1PA_N@Z
+; CHECK: void __cdecl f7(int, int *, int, int *, bool, bool, bool *)
+
+; FIXME: tests for more than 10 types?
+
+?g1@@YAXUS@@@Z
+; CHECK: void __cdecl g1(struct S)
+
+?g2@@YAXUS@@0@Z
+; CHECK: void __cdecl g2(struct S, struct S)
+
+?g3@@YAXUS@@0PAU1@1@Z
+; CHECK: void __cdecl g3(struct S, struct S, struct S *, struct S *)
+
+?g4@@YAXPBDPAUS@@01@Z
+; CHECK: void __cdecl g4(char const *, struct S *, char const *, struct S *)
+
+?mbb@S@@QAEX_N0@Z
+; CHECK: void __thiscall S::mbb(bool, bool)
+
+?h1@@YAXPBD0P6AXXZ1@Z
+; CHECK: void __cdecl h1(char const *, char const *, void (__cdecl *)(void), void (__cdecl *)(void))
+
+?h2@@YAXP6AXPAX@Z0@Z
+; CHECK: void __cdecl h2(void (__cdecl *)(void *), void *)
+
+?h3@@YAP6APAHPAH0@ZP6APAH00@Z10@Z
+; CHECK: int * (__cdecl * __cdecl h3(int * (__cdecl *)(int *, int *), int * (__cdecl *)(int *, int *), int *))(int *, int *)
+
+?foo@0@YAXXZ
+; CHECK: void __cdecl foo::foo(void)