[LLVM][Docs] Update for HowToSetUpLLVMStyleRTTI.rst, NFC.

This patch updates the document with some advanced use cases and examples on how to set up and use LLVM-style RTTI. It includes a few motivating examples to get readers comfortable with the concepts.

Reviewed By: lattner

Differential Revision: https://reviews.llvm.org/D126943
This commit is contained in:
bzcheeseman 2022-06-02 21:58:14 -07:00
parent 8555e59a71
commit 47231248f5
1 changed files with 99 additions and 0 deletions

View File

@ -467,3 +467,102 @@ E.g.
char Shape::ID = 0;
char Square::ID = 0;
char Circle::ID = 0;
Advanced Use Cases
==================
The underlying implementation of isa/cast/dyn_cast is all controlled through a
struct called ``CastInfo``. ``CastInfo`` provides 4 methods, ``isPossible``,
``doCast``, ``castFailed``, and ``doCastIfPossible``. These are for ``isa``,
``cast``, and ``dyn_cast``, in order. You can control the way your cast is
performed by creating a specialization of the ``CastInfo`` struct (to your
desired types) that provides the same static methods as the base ``CastInfo``
struct.
This can be a lot of boilerplate, so we also have what we call Cast Traits.
These are structs that provide one or more of the above methods so you can
factor out common casting patterns in your project. We provide a few in the
header file ready to be used, and we'll show a few examples motivating their
usage. These examples are not exhaustive, and adding new cast traits is easy
so users should feel free to add them to their project, or contribute them if
they're particularly useful!
Value to value casting
----------------------
In this case, we have a struct that is what we call 'nullable' - i.e. it is
constructible from ``nullptr`` and that results in a value you can tell is
invalid.
.. code-block:: c++
class SomeValue {
public:
SomeValue(void *ptr) : ptr(ptr) {}
void *getPointer() const { return ptr; }
bool isValid() const { return ptr != nullptr; }
private:
void *ptr;
};
Given something like this, we want to pass this object around by value, and we
would like to cast from objects of this type to some other set of objects. For
now, we assume that the types we want to cast *to* all provide ``classof``. So
we can use some provided cast traits like so:
.. code-block:: c++
template<typename T>
struct CastInfo<T, SomeValue>
: public CastIsPossible<T, SomeValue>,
public NullableValueCastFailed<T>,
public DefaultDoCastIfPossible<T, SomeValue, CastInfo<T, SomeValue>> {
static T doCast(SomeValue v) {
return T(v.getPointer());
}
};
Pointer to value casting
------------------------
Now given the value above ``SomeValue``, maybe we'd like to be able to cast to
that type from a char pointer type. So what we would do in that case is:
.. code-block:: c++
template<typename T>
struct CastInfo<SomeValue, T *>
: public NullableValueCastFailed<SomeValue>,
public DefaultDoCastIfPossible<SomeValue, T *,
CastInfo<SomeValue, T *>> {
static bool isPossible(const T *t) {
return std::is_same<T, char>::value;
}
static SomeValue doCast(const T *t) {
return SomeValue((void *)t);
}
};
This would enable us to cast from a ``char *`` to a SomeValue, if we wanted to.
Optional value casting
----------------------
When your types are not constructible from ``nullptr`` or there isn't a simple
way to tell when an object is invalid, you may want to use ``llvm::Optional``.
In those cases, you probably want something like this:
.. code-block:: c++
template<typename T>
struct CastInfo<T, SomeValue>
: public OptionalValueCast<T, SomeValue> {};
That cast trait requires that ``T`` is constructible from ``const SomeValue &``
but it enables casting like so:
.. code-block:: c++
SomeValue someVal = ...;
Optional<AnotherValue> valOr = dyn_cast<AnotherValue>(someVal);
With the ``_is_present`` variants, you can even do optional chaining like this:
.. code-block:: c++
Optional<SomeValue> someVal = ...;
Optional<AnotherValue> valOr = dyn_cast_if_present<AnotherValue>(someVal);
and ``valOr`` will be ``None`` if either ``someVal`` cannot be converted *or*
if ``someVal`` was also ``None``.