It looks to me like there is a limitation in the clang importer when importing simple constants defined like #define X_STD_SIZE 78.
If they are typecast like this...
#define X_STD_SIZE (char)78
...then it works fine but if they are typecast like this...
#define X_STD_SIZE (unsigned char)78
...then it does not work, the X_STD_SIZE constant is not imported and is not available to Swift.
I have tracked this down to code in lib/ClangImporter/ImportMacro.cpp the importMacro function (line 326 in my code).
This code is the problem...
// Handle tokens starting with a type cast
bool castTypeIsId = false;
if (numTokens > 3 &&
tokenI[0].is(clang::tok::l_paren) &&
(tokenI[1].is(clang::tok::identifier) ||
impl.getClangSema().isSimpleTypeSpecifier(tokenI[1].getKind())) &&
tokenI[2].is(clang::tok::r_paren)) {
if (!castType.isNull()) {
// this is a nested cast
return nullptr;
}
if (tokenI[1].is(clang::tok::identifier)) {
auto identifierInfo = tokenI[1].getIdentifierInfo();
if (identifierInfo->isStr("id")) {
castTypeIsId = true;
}
auto identifierName = identifierInfo->getName();
auto &identifier = impl.getClangASTContext().Idents.get(identifierName);
clang::sema::DelayedDiagnosticPool diagPool{
impl.getClangSema().DelayedDiagnostics.getCurrentPool()};
auto diagState = impl.getClangSema().DelayedDiagnostics.push(diagPool);
auto parsedType = impl.getClangSema().getTypeName(identifier,
clang::SourceLocation(),
/*scope*/nullptr);
impl.getClangSema().DelayedDiagnostics.popWithoutEmitting(diagState);
if (parsedType && diagPool.empty()) {
castType = parsedType.get();
} else {
return nullptr;
}
if (!castType->isBuiltinType() && !castTypeIsId) {
return nullptr;
}
} else {
auto builtinType = builtinTypeForToken(tokenI[1],
impl.getClangASTContext());
if (builtinType) {
castType = builtinType.getValue();
} else {
return nullptr;
}
}
tokenI += 3;
numTokens -= 3;
}
The problem is fairly obvious when you see it.
In the case when you're casting to char, there are four tokens in total, '(', 'char', ')', '78' and it all works. When you're casting to unsigned char, there are five tokens, '(', 'unsigned', 'char', ')', '78', so token 3 is 'char', not ')' and the test fails.
In order to fix this, the test needs to be more general, like...
if (numTokens > 3 &&
tokenI[0].is(clang::tok::l_paren) &&
(tokenI[1].is(clang::tok::identifier) ||
impl.getClangSema().isSimpleTypeSpecifier(tokenI[1].getKind())) &&
(tokenI[2].is(clang::tok::r_paren) || tokenE[-2].is(clang::tok::r_paren))) {
...but I'm not sure how this code works and what is best.
What do people think?