X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=docs%2FHowToSetUpLLVMStyleRTTI.rst;h=e0f865a141c7edef20e9a0ca4ab9279a4400f412;hb=fc699872e35ec794d7373680be6f1946fe8e9ca6;hp=a3403c2fc1d047563a84406cbd2bf9c720ef0a6f;hpb=40573998821fde7ffeabe8507f4c9e8c7cf762f6;p=oota-llvm.git diff --git a/docs/HowToSetUpLLVMStyleRTTI.rst b/docs/HowToSetUpLLVMStyleRTTI.rst index a3403c2fc1d..e0f865a141c 100644 --- a/docs/HowToSetUpLLVMStyleRTTI.rst +++ b/docs/HowToSetUpLLVMStyleRTTI.rst @@ -1,11 +1,7 @@ -.. _how-to-set-up-llvm-style-rtti: - ====================================================== How to set up LLVM-style RTTI for your class hierarchy ====================================================== -.. sectionauthor:: Sean Silva - .. contents:: Background @@ -77,8 +73,8 @@ steps: public: + /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.) + enum ShapeKind { - + SquareKind, - + CircleKind + + SK_Square, + + SK_Circle + }; +private: + const ShapeKind Kind; @@ -121,8 +117,8 @@ steps: public: /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.) enum ShapeKind { - SquareKind, - CircleKind + SK_Square, + SK_Circle }; private: const ShapeKind Kind; @@ -138,7 +134,7 @@ steps: double SideLength; public: - Square(double S) : SideLength(S) {} - + Square(double S) : Shape(SquareKind), SideLength(S) {} + + Square(double S) : Shape(SK_Square), SideLength(S) {} double computeArea() /* override */; }; @@ -146,7 +142,7 @@ steps: double Radius; public: - Circle(double R) : Radius(R) {} - + Circle(double R) : Shape(CircleKind), Radius(R) {} + + Circle(double R) : Shape(SK_Circle), Radius(R) {} double computeArea() /* override */; }; @@ -163,8 +159,8 @@ steps: public: /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.) enum ShapeKind { - SquareKind, - CircleKind + SK_Square, + SK_Circle }; private: const ShapeKind Kind; @@ -178,22 +174,22 @@ steps: class Square : public Shape { double SideLength; public: - Square(double S) : Shape(SquareKind), SideLength(S) {} + Square(double S) : Shape(SK_Square), SideLength(S) {} double computeArea() /* override */; + + static bool classof(const Shape *S) { - + return S->getKind() == SquareKind; + + return S->getKind() == SK_Square; + } }; class Circle : public Shape { double Radius; public: - Circle(double R) : Shape(CircleKind), Radius(R) {} + Circle(double R) : Shape(SK_Circle), Radius(R) {} double computeArea() /* override */; + + static bool classof(const Shape *S) { - + return S->getKind() == CircleKind; + + return S->getKind() == SK_Circle; + } }; @@ -264,10 +260,10 @@ from ``Square``, and so ``ShapeKind`` becomes: .. code-block:: c++ enum ShapeKind { - SquareKind, - + SpecialSquareKind, - + OtherSpecialSquareKind, - CircleKind + SK_Square, + + SK_SpecialSquare, + + SK_OtherSpecialSquare, + SK_Circle } Then in ``Square``, we would need to modify the ``classof`` like so: @@ -275,11 +271,11 @@ Then in ``Square``, we would need to modify the ``classof`` like so: .. code-block:: c++ - static bool classof(const Shape *S) { - - return S->getKind() == SquareKind; + - return S->getKind() == SK_Square; - } + static bool classof(const Shape *S) { - + return S->getKind() >= SquareKind && - + S->getKind() <= OtherSpecialSquareKind; + + return S->getKind() >= SK_Square && + + S->getKind() <= SK_OtherSpecialSquare; + } The reason that we need to test a range like this instead of just equality @@ -299,6 +295,78 @@ ordering right:: | OtherSpecialSquare | Circle +A Bug to be Aware Of +-------------------- + +The example just given opens the door to bugs where the ``classof``\s are +not updated to match the ``Kind`` enum when adding (or removing) classes to +(from) the hierarchy. + +Continuing the example above, suppose we add a ``SomewhatSpecialSquare`` as +a subclass of ``Square``, and update the ``ShapeKind`` enum like so: + +.. code-block:: c++ + + enum ShapeKind { + SK_Square, + SK_SpecialSquare, + SK_OtherSpecialSquare, + + SK_SomewhatSpecialSquare, + SK_Circle + } + +Now, suppose that we forget to update ``Square::classof()``, so it still +looks like: + +.. code-block:: c++ + + static bool classof(const Shape *S) { + // BUG: Returns false when S->getKind() == SK_SomewhatSpecialSquare, + // even though SomewhatSpecialSquare "is a" Square. + return S->getKind() >= SK_Square && + S->getKind() <= SK_OtherSpecialSquare; + } + +As the comment indicates, this code contains a bug. A straightforward and +non-clever way to avoid this is to introduce an explicit ``SK_LastSquare`` +entry in the enum when adding the first subclass(es). For example, we could +rewrite the example at the beginning of `Concrete Bases and Deeper +Hierarchies`_ as: + +.. code-block:: c++ + + enum ShapeKind { + SK_Square, + + SK_SpecialSquare, + + SK_OtherSpecialSquare, + + SK_LastSquare, + SK_Circle + } + ... + // Square::classof() + - static bool classof(const Shape *S) { + - return S->getKind() == SK_Square; + - } + + static bool classof(const Shape *S) { + + return S->getKind() >= SK_Square && + + S->getKind() <= SK_LastSquare; + + } + +Then, adding new subclasses is easy: + +.. code-block:: c++ + + enum ShapeKind { + SK_Square, + SK_SpecialSquare, + SK_OtherSpecialSquare, + + SK_SomewhatSpecialSquare, + SK_LastSquare, + SK_Circle + } + +Notice that ``Square::classof`` does not need to be changed. + .. _classof-contract: The Contract of ``classof``