Open
Description
// gcc -I/usr/lib/llvm-14/include/ test.c -L/usr/lib/llvm-14/lib/ -lLLVM-14 -lclang && ./a.out
#include <clang-c/Index.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
static enum CXChildVisitResult libclang_bug_inner(CXCursor cursor, CXCursor parent, CXClientData client_data)
{
enum CXCursorKind kind = clang_getCursorKind(cursor);
if (cursor.kind == CXCursor_VarDecl)
{
CXType ty = clang_getCursorType(cursor);
CXType ty_inner = clang_getPointeeType(ty);
CXString varname = clang_getCursorSpelling(cursor);
CXString tyname = clang_getTypeSpelling(ty);
CXString ty_inner_name = clang_getTypeSpelling(ty_inner);
printf("var [%s] type [%s] innertype [%s]\n",
clang_getCString(varname), clang_getCString(tyname), clang_getCString(ty_inner_name));
clang_disposeString(varname);
clang_disposeString(tyname);
clang_disposeString(ty_inner_name);
}
return CXChildVisit_Continue;
}
static void test_the_libclang_bug()
{
const char * src =
"typedef void fn1_t(void);\n"
"fn1_t* fn1;\n"
"typedef void (__attribute__((__noreturn__)) fn2_t)(void);\n"
"fn2_t* fn2;\n"
"typedef void (__attribute__((__cdecl__)) fn3_t)(void);\n"
"fn3_t* fn3;\n"
;
const char * argv[] = { "-x","c", "-target","i386-pc-windows-gnu" };
struct CXUnsavedFile input = { "input.c", src, strlen(src) };
CXIndex index = clang_createIndex(false, false);
CXTranslationUnit unit = clang_parseTranslationUnit(index, "input.c", argv, sizeof(argv)/sizeof(*argv),
&input, 1, CXTranslationUnit_None);
clang_visitChildren(clang_getTranslationUnitCursor(unit), libclang_bug_inner, NULL);
clang_disposeTranslationUnit(unit);
clang_disposeIndex(index);
}
int main() { test_the_libclang_bug(); }
Expected:
var [fn1] type [fn1_t *] innertype [fn1_t]
var [fn2] type [fn2_t *] innertype [fn2_t]
var [fn3] type [fn3_t *] innertype [fn3_t]
Actual:
var [fn1] type [fn1_t *] innertype [fn1_t]
var [fn2] type [fn2_t *] innertype [fn2_t]
var [fn3] type [fn3_t *] innertype [void (void)]
Tested by me on Clang/LLVM 14.0.6 (Debian), and by a friend on commit 756e7cf (five days ago).
Context: I'm trying to parse <windows.h>, and acquire the types and names of everything. Argument names disappear if typedefs are resolved, so I need fn3_t, not void(void).
I have a functional workaround (calling clang_visitChildren, expecting a CXCursor_TypeRef, and calling clang_getCursorReferenced on that), so this isn't a blocker, but it is kinda irritating.