Hello,
I recently ran into an issue where I wanted to use dyn_cast with a Multiple Inheritance hierarchy. LLVM’s help page on RTTI claims that it can be done, and that Clang’s Decl and DeclContext implement it; however, when I try to use it I run into odd behavior. Here’s my sample code which doesn’t work:
struct Base {
void *ptr;
bool hasInfo;
};
struct Info {
int size;
static bool classof(const Base *b) { return b->hasInfo; };
};
struct Child : public Base {
Child() {
this->ptr = this;
this->hasInfo = false;
}
};
struct ChildWithInfo : public Base, public Info {
ChildWithInfo() {
this->ptr = this;
this->hasInfo = true;
this->size = 10;
}
};
int main() {
Base *c = new Child();
Base *i = new ChildWithInfo();
try {
if (Info *inf = llvm::dyn_cast<Info>(c)) {
throw std::string("Casted a child to an info incorrectly");
}
if (Info *inf = llvm::dyn_cast<Info>(i)) {
if (inf->size != 10) {
std::ostringstream str;
str << "Object was sliced: expected 10 but got " << inf->size;
throw str.str();
}
} else {
throw std::string("Couldn't cast child with info to info");
}
} catch (std::string &msg) {
std::cout << msg << std::endl;
}
delete c;
delete i;
}
Basically the error is that when a Base
is cast to an Info
, it starts reading out of the same offset where ptr
is stored instead of size
.
How can I modify my class setup so that I can use this scheme safely?
Looking at Decl
and DeclContext
, it is unclear to me how they set things up so that the field offsets are correct, although I have a feeling
It has something to do with the LLVM_ALIGNAS
in the class declaration of Decl
.
Regards,
Riley Dulin