From 008ac35f23aca6a78c99eda55b56dde080447b77 Mon Sep 17 00:00:00 2001 From: Chen Steenvoorden Date: Tue, 27 Feb 2024 14:02:08 +0100 Subject: [PATCH] Fix demangling of namespaced type arguments The `Demangler` breaks up a mangled identifier into a list of "scopes": ```cpp namespace foo { // mangled name: _ZN3foo4funcEv // demangled name: foo::func // scopes: ["foo", "func"] void func() {} } ``` This does not work when the idenfitier is for a template with a namespaced type argument: ```cpp namespace bar { class Arg; } namespace foo { template void func() {} // mangled name: _ZN3foo4funcIN3bar3ArgIiEEEEvv // demangled name: foo::func // scopes: ["foo", "func"] template<> void func() {} } ``` The problem is that, when splitting the demangled name into scopes, it ignores the meaning of `<` and `>` characters, instead treating them as part of the name. The most hygienic solution is to replace the list of scopes with a more complex structure that can also hold type arguments. As this would require significant changes to the `Demangler`, and the `Demangler` is used in a few places where the effect of such changes would be unclear. I've opted for a quick and dirty solution for now. The list of scopes will still contain broken names, exactly as shown in the example above. When converting this list of scopes into a javascript name, the templates are removed *after* joining the scopes together instead of before. `cleanupTemplates` used to assume that the template parameters, if any, are at the end of the string passed to `cleanupTemplates`. This was true before because `>` is always at the end of a type name, or it is followed by `::`. But now, because `cleanupTemplates` is only called *after* joining the scopes back together, it can also be passed strings with multiple template parameters, or where the template parameters are not at the end of the string. `cleanupTemplates` is updated to handle these cases as well, splicing out template parameters from the middle of the string instead of just at the end. --- llvm/include/llvm/Cheerp/Demangler.h | 38 ++++++++-------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/llvm/include/llvm/Cheerp/Demangler.h b/llvm/include/llvm/Cheerp/Demangler.h index 468e9e49ac3a..ee7e904cd7db 100644 --- a/llvm/include/llvm/Cheerp/Demangler.h +++ b/llvm/include/llvm/Cheerp/Demangler.h @@ -100,17 +100,14 @@ class Demangler for (uint32_t i=(doCleanup && isNamespaceClient())?1:0; i=0; i--) + for (char c : name) { - bool isSpecial = false; - if (name[i] == close) - { - balance++; - isSpecial = true; - } - else if (name[i] == open) - { - balance--; - isSpecial = true; - } - - if (isSpecial && balance == 0) - { - lastBalanced = i; - } + if (c == '<') + balance += 1; + if (balance == 0) + res += c; + if (c == '>') + balance -= 1; } - return std::string(name, 0, lastBalanced); + return res; } std::vector scopes; std::string functionName{""};