I am trying to generate the Data Layout for a class. Specifically, I want
- the size of an object of type
X - the alignment of an object of type
X - the offset within an object of type
Xof each data component (base or member).
I can easily enough get 1 and 2. I can also easily get 3 for each member of X.
In addition, given a class, I can obtain the cursor for each of its base classes, and can traverse that to the root and build an inheritance graph.
However, I can't figure out how to get the offset of each base of class X.
Ultimately, I want the offsets of all members of X, and all the members of all bases of X, with their offsets relative to X.
Basically, I want the information that is described in Chapter 2: Data Layout from the Itanium C++ ABI for any arbitrary class, X.
I could imagine that this information is not available in the AST, and is only resolved in a specific backend targeting itanium, but other ABI specific information is available (like offsets of any class since the standard does not define class layout).
EDIT - EDIT - EDIT
After reading the comment by @Scott McPeak, I took a peek (see what I did there) at the internals, enough to hack something that seems to work, but likely has major issues.
Here is my somewhat feeble attempt using some of the C++ classes that are used to implement libclang. I implemented it as an extension of the libclang API, just to make it easier for me to consume and test. It does what I want, and maybe that makes things a bit more clear for those trying to help.
I'm sure I'm doing something terribly wrong, so I would love a proper answer, especially if what I want can be done somehow with the current libclang API.
It is based on clang_Type_getOffsetOf.
Obviously, CXTypeLayoutError_InvalidFieldName should be something different, or maybe CXTypeLayoutError_InvalidBase of aliased to CXTypeLayoutError_InvalidFieldNameOrBase. In addition, it returns the offset in bits, for consistency with the member offsets, even though I'm 99.9999% sure that there is no way a base class can have an offset in bits.
long long clang_Type_getOffsetOfBase(CXType PT,
const CXIdxBaseClassInfo *BaseInfo) {
// check that PT is not incomplete/dependent
CXCursor PC = clang_getTypeDeclaration(PT);
long long Error = validateFieldParentType(PC,PT);
if (Error < 0)
return Error;
// get the record decl for PT
ASTContext &Ctx = cxtu::getASTUnit(GetTU(PT))->getASTContext();
const CXXRecordDecl *RD =
dyn_cast_or_null<CXXRecordDecl>(cxcursor::getCursorDecl(PC));
if (!RD)
return CXTypeLayoutError_Invalid;
// get the record decl for the base
if (BaseInfo) {
if (auto Spec = cxcursor::getCursorCXXBaseSpecifier(BaseInfo->cursor)) {
if (auto BaseDecl = Spec->getType()->getAsCXXRecordDecl()) {
return Ctx.toBits(
Ctx.getASTRecordLayout(RD).getBaseClassOffset(BaseDecl));
}
}
}
return CXTypeLayoutError_InvalidFieldName;
}