llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.78k stars 11.9k forks source link

[libclang] Type names are getting incorrectly canonicalized in template arguments of full specializations #92371

Open HolyBlackCat opened 5 months ago

HolyBlackCat commented 5 months ago

If you have an explicit (full) template specialization, Clang preserves the exact spelling of the template arguments you used, and then uses them when you ask for a canonical type name.

Here's an example code:

namespace NS
{
    template <typename T> struct A {};

    struct B {};
    using C = B;

    template <> struct A<C> {};
}

NS::A<NS::B> foo();

When printing the return type of foo using clang_getTypeSpelling(clang_getCanonicalType(clang_getCursorType(cursor))), I get NS::A<C>. (The part <C> is spelled exactly as in the specialization. If I specialize using <B> instead, I get that. Same for any qualifiers, etc.)

This is annoying, because I'm trying to use canonical names to generate some code, and I expect them to be fully qualified (maybe they aren't the right tool for the job, but I didn't find anything else in the C API).

This might've been introduced in LLVM 16 along with similar changes to __PRETTY_FUNCTION__.

Here's a small snippet using libclang that can be used to test this:

#include <clang-c/Index.h>
#include <stdio.h>

static enum CXChildVisitResult visitor(CXCursor cursor, CXCursor parent, CXClientData client_data)
{
    (void)parent;
    (void)client_data;

    CXString str = clang_getTypeSpelling(clang_getCursorType(cursor));
    printf("%s\n", clang_getCString(str));
    clang_disposeString(str);

    return CXChildVisit_Recurse;
}

int main(int argc, char **argv)
{
    CXIndex idx = clang_createIndex(0, 1);
    CXTranslationUnit tu = clang_parseTranslationUnit(idx, 0, (const char **)argv, argc, 0, 0, 0);
    if (!tu)
        return 1;

    clang_visitChildren(clang_getTranslationUnitCursor(tu), visitor, 0);

    clang_disposeTranslationUnit(tu);
    clang_disposeIndex(idx);
}