Skip to content

libclang: clang_getPointeeType dereferences typedefs to functions with calling convention attribute #144337

Open
@Alcaro

Description

@Alcaro
// 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions