Riley Dulin via llvm-dev
2017-Jun-28 23:06 UTC
[llvm-dev] 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 -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170628/b54b7c58/attachment.html>
Craig Topper via llvm-dev
2017-Jun-29 01:46 UTC
[llvm-dev] Multiple Inheritance with dyn_cast
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. On Wed, Jun 28, 2017 at 6:04 PM Riley Dulin via llvm-dev < llvm-dev at lists.llvm.org> wrote:> 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 > > > _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >-- ~Craig -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170629/0630490f/attachment.html>
Craig Topper via llvm-dev
2017-Jun-29 04:00 UTC
[llvm-dev] Multiple Inheritance with dyn_cast
That should have said DeclBase.h On Wed, Jun 28, 2017 at 6:46 PM Craig Topper <craig.topper at gmail.com> wrote:> 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. > > On Wed, Jun 28, 2017 at 6:04 PM Riley Dulin via llvm-dev < > llvm-dev at lists.llvm.org> wrote: > >> 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 >> >> >> _______________________________________________ >> LLVM Developers mailing list >> llvm-dev at lists.llvm.org >> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev >> > -- > ~Craig >-- ~Craig -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170629/7838820e/attachment.html>