[llvm-commits] [llvm] r165768 - /llvm/trunk/docs/HowToSetUpLLVMStyleRTTI.rst

Sean Silva silvas at purdue.edu
Thu Oct 11 16:30:53 PDT 2012


Author: silvas
Date: Thu Oct 11 18:30:52 2012
New Revision: 165768

URL: http://llvm.org/viewvc/llvm-project?rev=165768&view=rev
Log:
docs: Improve HowToSetUpLLVMStyleRTTI.

* Fix confusing explanation regarding abstract classes.

* Clarify auto-upcasting and why `Shape` doesn't need a `classof()`.

* Add section `Rules of Thumb` with some quick summary tips.

Modified:
    llvm/trunk/docs/HowToSetUpLLVMStyleRTTI.rst

Modified: llvm/trunk/docs/HowToSetUpLLVMStyleRTTI.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/HowToSetUpLLVMStyleRTTI.rst?rev=165768&r1=165767&r2=165768&view=diff
==============================================================================
--- llvm/trunk/docs/HowToSetUpLLVMStyleRTTI.rst (original)
+++ llvm/trunk/docs/HowToSetUpLLVMStyleRTTI.rst Thu Oct 11 18:30:52 2012
@@ -65,10 +65,9 @@
 
       #include "llvm/Support/Casting.h"
 
-
 #. In the base class, introduce an enum which discriminates all of the
-   different classes in the hierarchy, and stash the enum value somewhere in
-   the base class.
+   different concrete classes in the hierarchy, and stash the enum value
+   somewhere in the base class.
 
    Here is the code after introducing this change:
 
@@ -103,7 +102,7 @@
    You might wonder why the ``Kind`` enum doesn't have an entry for
    ``Shape``. The reason for this is that since ``Shape`` is abstract
    (``computeArea() = 0;``), you will never actually have non-derived
-   instances of exactly that class (only subclasses).  See `Concrete Bases
+   instances of exactly that class (only subclasses). See `Concrete Bases
    and Deeper Hierarchies`_ for information on how to deal with
    non-abstract bases. It's worth mentioning here that unlike
    ``dynamic_cast<>``, LLVM-style RTTI can be used (and is often used) for
@@ -199,25 +198,11 @@
        };
 
    The job of ``classof`` is to dynamically determine whether an object of
-   a base class is in fact of a particular derived class. The argument to
-   ``classof`` should always be an *ancestor* class because the
-   implementation has logic to allow and optimize away
-   upcasts/up-``isa<>``'s automatically. It is as though every class
-   ``Foo`` automatically has a ``classof`` like:
-
-   .. code-block:: c++
-
-      class Foo {
-        [...]
-        static bool classof(const Foo *) { return true; }
-        [...]
-      };
-
-   In order to downcast a type ``Base`` to a type ``Derived``, there needs
-   to be a ``classof`` in ``Derived`` which will accept an object of type
-   ``Base``.
+   a base class is in fact of a particular derived class.  In order to
+   downcast a type ``Base`` to a type ``Derived``, there needs to be a
+   ``classof`` in ``Derived`` which will accept an object of type ``Base``.
 
-   To be concrete, in the following code:
+   To be concrete, consider the following code:
 
    .. code-block:: c++
 
@@ -226,11 +211,35 @@
         /* do something ... */
       }
 
-   The code of ``isa<>`` will eventually boil down---after template
-   instantiation and some other machinery---to a check roughly like
-   ``Circle::classof(S)``. For more information, see
+   The code of the ``isa<>`` test in this code will eventually boil
+   down---after template instantiation and some other machinery---to a
+   check roughly like ``Circle::classof(S)``. For more information, see
    :ref:`classof-contract`.
 
+   The argument to ``classof`` should always be an *ancestor* class because
+   the implementation has logic to allow and optimize away
+   upcasts/up-``isa<>``'s automatically. It is as though every class
+   ``Foo`` automatically has a ``classof`` like:
+
+   .. code-block:: c++
+
+      class Foo {
+        [...]
+        template <class T>
+        static bool classof(const T *,
+                            ::llvm::enable_if_c<
+                              ::llvm::is_base_of<Foo, T>::value
+                            >::type* = 0) { return true; }
+        [...]
+      };
+
+   Note that this is the reason that we did not need to introduce a
+   ``classof`` into ``Shape``: all relevant classes derive from ``Shape``,
+   and ``Shape`` itself is abstract (has no entry in the ``Kind`` enum),
+   so this notional inferred ``classof`` is all we need. See `Concrete
+   Bases and Deeper Hierarchies`_ for more information about how to extend
+   this example to more general hierarchies.
+
 Although for this small example setting up LLVM-style RTTI seems like a lot
 of "boilerplate", if your classes are doing anything interesting then this
 will end up being a tiny fraction of the code.
@@ -240,7 +249,16 @@
 
 For concrete bases (i.e. non-abstract interior nodes of the inheritance
 tree), the ``Kind`` check inside ``classof`` needs to be a bit more
-complicated. Say that ``SpecialSquare`` and ``OtherSpecialSquare`` derive
+complicated. The situation differs from the example above in that
+
+* Since the class is concrete, it must itself have an entry in the ``Kind``
+  enum because it is possible to have objects with this class as a dynamic
+  type.
+
+* Since the class has children, the check inside ``classof`` must take them
+  into account.
+
+Say that ``SpecialSquare`` and ``OtherSpecialSquare`` derive
 from ``Square``, and so ``ShapeKind`` becomes:
 
 .. code-block:: c++
@@ -297,3 +315,18 @@
    ``simplify_type``. However, those two need reference documentation in
    the form of doxygen comments as well. We need the doxygen so that we can
    say "for full details, see http://llvm.org/doxygen/..."
+
+Rules of Thumb
+==============
+
+#. The ``Kind`` enum should have one entry per concrete class, ordered
+   according to a preorder traversal of the inheritance tree.
+#. The argument to ``classof`` should be a ``const Base *``, where ``Base``
+   is some ancestor in the inheritance hierarchy. The argument should
+   *never* be a derived class or the class itself: the template machinery
+   for ``isa<>`` already handles this case and optimizes it.
+#. For each class in the hierarchy that has no children, implement a
+   ``classof`` that checks only against its ``Kind``.
+#. For each class in the hierarchy that has children, implement a
+   ``classof`` that checks a range of the first child's ``Kind`` and the
+   last child's ``Kind``.





More information about the llvm-commits mailing list