Multiple Inheritance with dyn_cast

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

I think the magic for Decl/DeclContext is the overrides of “doit” at the bottom of DeclBase. This is replacing the default casting implementation to make this work. Unfortunately I’m on my phone so I can’t get a lot more details.

That should have said DeclBase.h