Branch data Line data Source code
1 : : //===- llvm/Support/Casting.h - Allow flexible, checked, casts --*- C++ -*-===//
2 : : //
3 : : // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 : : // See https://llvm.org/LICENSE.txt for license information.
5 : : // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 : : //
7 : : //===----------------------------------------------------------------------===//
8 : : //
9 : : // This file defines the isa<X>(), cast<X>(), dyn_cast<X>(),
10 : : // cast_if_present<X>(), and dyn_cast_if_present<X>() templates.
11 : : //
12 : : //===----------------------------------------------------------------------===//
13 : :
14 : : #ifndef LLVM_SUPPORT_CASTING_H
15 : : #define LLVM_SUPPORT_CASTING_H
16 : :
17 : : #include "llvm/Support/Compiler.h"
18 : : #include "llvm/Support/type_traits.h"
19 : : #include <cassert>
20 : : #include <memory>
21 : : #include <optional>
22 : : #include <type_traits>
23 : :
24 : : namespace llvm {
25 : :
26 : : //===----------------------------------------------------------------------===//
27 : : // simplify_type
28 : : //===----------------------------------------------------------------------===//
29 : :
30 : : /// Define a template that can be specialized by smart pointers to reflect the
31 : : /// fact that they are automatically dereferenced, and are not involved with the
32 : : /// template selection process... the default implementation is a noop.
33 : : // TODO: rename this and/or replace it with other cast traits.
34 : : template <typename From> struct simplify_type {
35 : : using SimpleType = From; // The real type this represents...
36 : :
37 : : // An accessor to get the real value...
38 : 0 : static SimpleType &getSimplifiedValue(From &Val) { return Val; }
39 : : };
40 : :
41 : : template <typename From> struct simplify_type<const From> {
42 : : using NonConstSimpleType = typename simplify_type<From>::SimpleType;
43 : : using SimpleType = typename add_const_past_pointer<NonConstSimpleType>::type;
44 : : using RetType =
45 : : typename add_lvalue_reference_if_not_pointer<SimpleType>::type;
46 : :
47 : 0 : static RetType getSimplifiedValue(const From &Val) {
48 : 0 : return simplify_type<From>::getSimplifiedValue(const_cast<From &>(Val));
49 : : }
50 : : };
51 : :
52 : : // TODO: add this namespace once everyone is switched to using the new
53 : : // interface.
54 : : // namespace detail {
55 : :
56 : : //===----------------------------------------------------------------------===//
57 : : // isa_impl
58 : : //===----------------------------------------------------------------------===//
59 : :
60 : : // The core of the implementation of isa<X> is here; To and From should be
61 : : // the names of classes. This template can be specialized to customize the
62 : : // implementation of isa<> without rewriting it from scratch.
63 : : template <typename To, typename From, typename Enabler = void> struct isa_impl {
64 : 0 : static inline bool doit(const From &Val) { return To::classof(&Val); }
65 : : };
66 : :
67 : : // Always allow upcasts, and perform no dynamic check for them.
68 : : template <typename To, typename From>
69 : : struct isa_impl<To, From, std::enable_if_t<std::is_base_of_v<To, From>>> {
70 : : static inline bool doit(const From &) { return true; }
71 : : };
72 : :
73 : : template <typename To, typename From> struct isa_impl_cl {
74 : : static inline bool doit(const From &Val) {
75 : : return isa_impl<To, From>::doit(Val);
76 : : }
77 : : };
78 : :
79 : : template <typename To, typename From> struct isa_impl_cl<To, const From> {
80 : 0 : static inline bool doit(const From &Val) {
81 : 0 : return isa_impl<To, From>::doit(Val);
82 : : }
83 : : };
84 : :
85 : : template <typename To, typename From>
86 : : struct isa_impl_cl<To, const std::unique_ptr<From>> {
87 : : static inline bool doit(const std::unique_ptr<From> &Val) {
88 : : assert(Val && "isa<> used on a null pointer");
89 : : return isa_impl_cl<To, From>::doit(*Val);
90 : : }
91 : : };
92 : :
93 : : template <typename To, typename From> struct isa_impl_cl<To, From *> {
94 : : static inline bool doit(const From *Val) {
95 : : assert(Val && "isa<> used on a null pointer");
96 : : return isa_impl<To, From>::doit(*Val);
97 : : }
98 : : };
99 : :
100 : : template <typename To, typename From> struct isa_impl_cl<To, From *const> {
101 : : static inline bool doit(const From *Val) {
102 : : assert(Val && "isa<> used on a null pointer");
103 : : return isa_impl<To, From>::doit(*Val);
104 : : }
105 : : };
106 : :
107 : : template <typename To, typename From> struct isa_impl_cl<To, const From *> {
108 : 0 : static inline bool doit(const From *Val) {
109 [ # # ]: 0 : assert(Val && "isa<> used on a null pointer");
110 : 0 : return isa_impl<To, From>::doit(*Val);
111 : : }
112 : : };
113 : :
114 : : template <typename To, typename From>
115 : : struct isa_impl_cl<To, const From *const> {
116 : : static inline bool doit(const From *Val) {
117 : : assert(Val && "isa<> used on a null pointer");
118 : : return isa_impl<To, From>::doit(*Val);
119 : : }
120 : : };
121 : :
122 : : template <typename To, typename From, typename SimpleFrom>
123 : : struct isa_impl_wrap {
124 : : // When From != SimplifiedType, we can simplify the type some more by using
125 : : // the simplify_type template.
126 : 0 : static bool doit(const From &Val) {
127 : : return isa_impl_wrap<To, SimpleFrom,
128 : : typename simplify_type<SimpleFrom>::SimpleType>::
129 [ # # # # ]: 0 : doit(simplify_type<const From>::getSimplifiedValue(Val));
130 : : }
131 : : };
132 : :
133 : : template <typename To, typename FromTy>
134 : : struct isa_impl_wrap<To, FromTy, FromTy> {
135 : : // When From == SimpleType, we are as simple as we are going to get.
136 : 0 : static bool doit(const FromTy &Val) {
137 : 0 : return isa_impl_cl<To, FromTy>::doit(Val);
138 : : }
139 : : };
140 : :
141 : : //===----------------------------------------------------------------------===//
142 : : // cast_retty + cast_retty_impl
143 : : //===----------------------------------------------------------------------===//
144 : :
145 : : template <class To, class From> struct cast_retty;
146 : :
147 : : // Calculate what type the 'cast' function should return, based on a requested
148 : : // type of To and a source type of From.
149 : : template <class To, class From> struct cast_retty_impl {
150 : : using ret_type = To &; // Normal case, return Ty&
151 : : };
152 : : template <class To, class From> struct cast_retty_impl<To, const From> {
153 : : using ret_type = const To &; // Normal case, return Ty&
154 : : };
155 : :
156 : : template <class To, class From> struct cast_retty_impl<To, From *> {
157 : : using ret_type = To *; // Pointer arg case, return Ty*
158 : : };
159 : :
160 : : template <class To, class From> struct cast_retty_impl<To, const From *> {
161 : : using ret_type = const To *; // Constant pointer arg case, return const Ty*
162 : : };
163 : :
164 : : template <class To, class From> struct cast_retty_impl<To, const From *const> {
165 : : using ret_type = const To *; // Constant pointer arg case, return const Ty*
166 : : };
167 : :
168 : : template <class To, class From>
169 : : struct cast_retty_impl<To, std::unique_ptr<From>> {
170 : : private:
171 : : using PointerType = typename cast_retty_impl<To, From *>::ret_type;
172 : : using ResultType = std::remove_pointer_t<PointerType>;
173 : :
174 : : public:
175 : : using ret_type = std::unique_ptr<ResultType>;
176 : : };
177 : :
178 : : template <class To, class From, class SimpleFrom> struct cast_retty_wrap {
179 : : // When the simplified type and the from type are not the same, use the type
180 : : // simplifier to reduce the type, then reuse cast_retty_impl to get the
181 : : // resultant type.
182 : : using ret_type = typename cast_retty<To, SimpleFrom>::ret_type;
183 : : };
184 : :
185 : : template <class To, class FromTy> struct cast_retty_wrap<To, FromTy, FromTy> {
186 : : // When the simplified type is equal to the from type, use it directly.
187 : : using ret_type = typename cast_retty_impl<To, FromTy>::ret_type;
188 : : };
189 : :
190 : : template <class To, class From> struct cast_retty {
191 : : using ret_type = typename cast_retty_wrap<
192 : : To, From, typename simplify_type<From>::SimpleType>::ret_type;
193 : : };
194 : :
195 : : //===----------------------------------------------------------------------===//
196 : : // cast_convert_val
197 : : //===----------------------------------------------------------------------===//
198 : :
199 : : // Ensure the non-simple values are converted using the simplify_type template
200 : : // that may be specialized by smart pointers...
201 : : //
202 : : template <class To, class From, class SimpleFrom> struct cast_convert_val {
203 : : // This is not a simple type, use the template to simplify it...
204 : : static typename cast_retty<To, From>::ret_type doit(const From &Val) {
205 : : return cast_convert_val<To, SimpleFrom,
206 : : typename simplify_type<SimpleFrom>::SimpleType>::
207 : : doit(simplify_type<From>::getSimplifiedValue(const_cast<From &>(Val)));
208 : : }
209 : : };
210 : :
211 : : template <class To, class FromTy> struct cast_convert_val<To, FromTy, FromTy> {
212 : : // If it's a reference, switch to a pointer to do the cast and then deref it.
213 : : static typename cast_retty<To, FromTy>::ret_type doit(const FromTy &Val) {
214 : : return *(std::remove_reference_t<typename cast_retty<To, FromTy>::ret_type>
215 : : *)&const_cast<FromTy &>(Val);
216 : : }
217 : : };
218 : :
219 : : template <class To, class FromTy>
220 : : struct cast_convert_val<To, FromTy *, FromTy *> {
221 : : // If it's a pointer, we can use c-style casting directly.
222 : 0 : static typename cast_retty<To, FromTy *>::ret_type doit(const FromTy *Val) {
223 : : return (typename cast_retty<To, FromTy *>::ret_type) const_cast<FromTy *>(
224 : 0 : Val);
225 : : }
226 : : };
227 : :
228 : : //===----------------------------------------------------------------------===//
229 : : // is_simple_type
230 : : //===----------------------------------------------------------------------===//
231 : :
232 : : template <class X> struct is_simple_type {
233 : : static const bool value =
234 : : std::is_same_v<X, typename simplify_type<X>::SimpleType>;
235 : : };
236 : :
237 : : // } // namespace detail
238 : :
239 : : //===----------------------------------------------------------------------===//
240 : : // CastIsPossible
241 : : //===----------------------------------------------------------------------===//
242 : :
243 : : /// This struct provides a way to check if a given cast is possible. It provides
244 : : /// a static function called isPossible that is used to check if a cast can be
245 : : /// performed. It should be overridden like this:
246 : : ///
247 : : /// template<> struct CastIsPossible<foo, bar> {
248 : : /// static inline bool isPossible(const bar &b) {
249 : : /// return bar.isFoo();
250 : : /// }
251 : : /// };
252 : : template <typename To, typename From, typename Enable = void>
253 : : struct CastIsPossible {
254 : 0 : static inline bool isPossible(const From &f) {
255 : : return isa_impl_wrap<
256 : : To, const From,
257 : 0 : typename simplify_type<const From>::SimpleType>::doit(f);
258 : : }
259 : : };
260 : :
261 : : // Needed for optional unwrapping. This could be implemented with isa_impl, but
262 : : // we want to implement things in the new method and move old implementations
263 : : // over. In fact, some of the isa_impl templates should be moved over to
264 : : // CastIsPossible.
265 : : template <typename To, typename From>
266 : : struct CastIsPossible<To, std::optional<From>> {
267 : : static inline bool isPossible(const std::optional<From> &f) {
268 : : assert(f && "CastIsPossible::isPossible called on a nullopt!");
269 : : return isa_impl_wrap<
270 : : To, const From,
271 : : typename simplify_type<const From>::SimpleType>::doit(*f);
272 : : }
273 : : };
274 : :
275 : : /// Upcasting (from derived to base) and casting from a type to itself should
276 : : /// always be possible.
277 : : template <typename To, typename From>
278 : : struct CastIsPossible<To, From, std::enable_if_t<std::is_base_of_v<To, From>>> {
279 : : static inline bool isPossible(const From &f) { return true; }
280 : : };
281 : :
282 : : //===----------------------------------------------------------------------===//
283 : : // Cast traits
284 : : //===----------------------------------------------------------------------===//
285 : :
286 : : /// All of these cast traits are meant to be implementations for useful casts
287 : : /// that users may want to use that are outside the standard behavior. An
288 : : /// example of how to use a special cast called `CastTrait` is:
289 : : ///
290 : : /// template<> struct CastInfo<foo, bar> : public CastTrait<foo, bar> {};
291 : : ///
292 : : /// Essentially, if your use case falls directly into one of the use cases
293 : : /// supported by a given cast trait, simply inherit your special CastInfo
294 : : /// directly from one of these to avoid having to reimplement the boilerplate
295 : : /// `isPossible/castFailed/doCast/doCastIfPossible`. A cast trait can also
296 : : /// provide a subset of those functions.
297 : :
298 : : /// This cast trait just provides castFailed for the specified `To` type to make
299 : : /// CastInfo specializations more declarative. In order to use this, the target
300 : : /// result type must be `To` and `To` must be constructible from `nullptr`.
301 : : template <typename To> struct NullableValueCastFailed {
302 : : static To castFailed() { return To(nullptr); }
303 : : };
304 : :
305 : : /// This cast trait just provides the default implementation of doCastIfPossible
306 : : /// to make CastInfo specializations more declarative. The `Derived` template
307 : : /// parameter *must* be provided for forwarding castFailed and doCast.
308 : : template <typename To, typename From, typename Derived>
309 : : struct DefaultDoCastIfPossible {
310 : : static To doCastIfPossible(From f) {
311 : : if (!Derived::isPossible(f))
312 : : return Derived::castFailed();
313 : : return Derived::doCast(f);
314 : : }
315 : : };
316 : :
317 : : namespace detail {
318 : : /// A helper to derive the type to use with `Self` for cast traits, when the
319 : : /// provided CRTP derived type is allowed to be void.
320 : : template <typename OptionalDerived, typename Default>
321 : : using SelfType = std::conditional_t<std::is_same_v<OptionalDerived, void>,
322 : : Default, OptionalDerived>;
323 : : } // namespace detail
324 : :
325 : : /// This cast trait provides casting for the specific case of casting to a
326 : : /// value-typed object from a pointer-typed object. Note that `To` must be
327 : : /// nullable/constructible from a pointer to `From` to use this cast.
328 : : template <typename To, typename From, typename Derived = void>
329 : : struct ValueFromPointerCast
330 : : : public CastIsPossible<To, From *>,
331 : : public NullableValueCastFailed<To>,
332 : : public DefaultDoCastIfPossible<
333 : : To, From *,
334 : : detail::SelfType<Derived, ValueFromPointerCast<To, From>>> {
335 : : static inline To doCast(From *f) { return To(f); }
336 : : };
337 : :
338 : : /// This cast trait provides std::unique_ptr casting. It has the semantics of
339 : : /// moving the contents of the input unique_ptr into the output unique_ptr
340 : : /// during the cast. It's also a good example of how to implement a move-only
341 : : /// cast.
342 : : template <typename To, typename From, typename Derived = void>
343 : : struct UniquePtrCast : public CastIsPossible<To, From *> {
344 : : using Self = detail::SelfType<Derived, UniquePtrCast<To, From>>;
345 : : using CastResultType = std::unique_ptr<
346 : : std::remove_reference_t<typename cast_retty<To, From>::ret_type>>;
347 : :
348 : : static inline CastResultType doCast(std::unique_ptr<From> &&f) {
349 : : return CastResultType((typename CastResultType::element_type *)f.release());
350 : : }
351 : :
352 : : static inline CastResultType castFailed() { return CastResultType(nullptr); }
353 : :
354 : : static inline CastResultType doCastIfPossible(std::unique_ptr<From> &f) {
355 : : if (!Self::isPossible(f.get()))
356 : : return castFailed();
357 : : return doCast(std::move(f));
358 : : }
359 : : };
360 : :
361 : : /// This cast trait provides std::optional<T> casting. This means that if you
362 : : /// have a value type, you can cast it to another value type and have dyn_cast
363 : : /// return an std::optional<T>.
364 : : template <typename To, typename From, typename Derived = void>
365 : : struct OptionalValueCast
366 : : : public CastIsPossible<To, From>,
367 : : public DefaultDoCastIfPossible<
368 : : std::optional<To>, From,
369 : : detail::SelfType<Derived, OptionalValueCast<To, From>>> {
370 : : static inline std::optional<To> castFailed() { return std::optional<To>{}; }
371 : :
372 : : static inline std::optional<To> doCast(const From &f) { return To(f); }
373 : : };
374 : :
375 : : /// Provides a cast trait that strips `const` from types to make it easier to
376 : : /// implement a const-version of a non-const cast. It just removes boilerplate
377 : : /// and reduces the amount of code you as the user need to implement. You can
378 : : /// use it like this:
379 : : ///
380 : : /// template<> struct CastInfo<foo, bar> {
381 : : /// ...verbose implementation...
382 : : /// };
383 : : ///
384 : : /// template<> struct CastInfo<foo, const bar> : public
385 : : /// ConstStrippingForwardingCast<foo, const bar, CastInfo<foo, bar>> {};
386 : : ///
387 : : template <typename To, typename From, typename ForwardTo>
388 : : struct ConstStrippingForwardingCast {
389 : : // Remove the pointer if it exists, then we can get rid of consts/volatiles.
390 : : using DecayedFrom = std::remove_cv_t<std::remove_pointer_t<From>>;
391 : : // Now if it's a pointer, add it back. Otherwise, we want a ref.
392 : : using NonConstFrom =
393 : : std::conditional_t<std::is_pointer_v<From>, DecayedFrom *, DecayedFrom &>;
394 : :
395 : 0 : static inline bool isPossible(const From &f) {
396 : 0 : return ForwardTo::isPossible(const_cast<NonConstFrom>(f));
397 : : }
398 : :
399 : : static inline decltype(auto) castFailed() { return ForwardTo::castFailed(); }
400 : :
401 : 0 : static inline decltype(auto) doCast(const From &f) {
402 : 0 : return ForwardTo::doCast(const_cast<NonConstFrom>(f));
403 : : }
404 : :
405 : : static inline decltype(auto) doCastIfPossible(const From &f) {
406 : : return ForwardTo::doCastIfPossible(const_cast<NonConstFrom>(f));
407 : : }
408 : : };
409 : :
410 : : /// Provides a cast trait that uses a defined pointer to pointer cast as a base
411 : : /// for reference-to-reference casts. Note that it does not provide castFailed
412 : : /// and doCastIfPossible because a pointer-to-pointer cast would likely just
413 : : /// return `nullptr` which could cause nullptr dereference. You can use it like
414 : : /// this:
415 : : ///
416 : : /// template <> struct CastInfo<foo, bar *> { ... verbose implementation... };
417 : : ///
418 : : /// template <>
419 : : /// struct CastInfo<foo, bar>
420 : : /// : public ForwardToPointerCast<foo, bar, CastInfo<foo, bar *>> {};
421 : : ///
422 : : template <typename To, typename From, typename ForwardTo>
423 : : struct ForwardToPointerCast {
424 : : static inline bool isPossible(const From &f) {
425 : : return ForwardTo::isPossible(&f);
426 : : }
427 : :
428 : : static inline decltype(auto) doCast(const From &f) {
429 : : return *ForwardTo::doCast(&f);
430 : : }
431 : : };
432 : :
433 : : //===----------------------------------------------------------------------===//
434 : : // CastInfo
435 : : //===----------------------------------------------------------------------===//
436 : :
437 : : /// This struct provides a method for customizing the way a cast is performed.
438 : : /// It inherits from CastIsPossible, to support the case of declaring many
439 : : /// CastIsPossible specializations without having to specialize the full
440 : : /// CastInfo.
441 : : ///
442 : : /// In order to specialize different behaviors, specify different functions in
443 : : /// your CastInfo specialization.
444 : : /// For isa<> customization, provide:
445 : : ///
446 : : /// `static bool isPossible(const From &f)`
447 : : ///
448 : : /// For cast<> customization, provide:
449 : : ///
450 : : /// `static To doCast(const From &f)`
451 : : ///
452 : : /// For dyn_cast<> and the *_if_present<> variants' customization, provide:
453 : : ///
454 : : /// `static To castFailed()` and `static To doCastIfPossible(const From &f)`
455 : : ///
456 : : /// Your specialization might look something like this:
457 : : ///
458 : : /// template<> struct CastInfo<foo, bar> : public CastIsPossible<foo, bar> {
459 : : /// static inline foo doCast(const bar &b) {
460 : : /// return foo(const_cast<bar &>(b));
461 : : /// }
462 : : /// static inline foo castFailed() { return foo(); }
463 : : /// static inline foo doCastIfPossible(const bar &b) {
464 : : /// if (!CastInfo<foo, bar>::isPossible(b))
465 : : /// return castFailed();
466 : : /// return doCast(b);
467 : : /// }
468 : : /// };
469 : :
470 : : // The default implementations of CastInfo don't use cast traits for now because
471 : : // we need to specify types all over the place due to the current expected
472 : : // casting behavior and the way cast_retty works. New use cases can and should
473 : : // take advantage of the cast traits whenever possible!
474 : :
475 : : template <typename To, typename From, typename Enable = void>
476 : : struct CastInfo : public CastIsPossible<To, From> {
477 : : using Self = CastInfo<To, From, Enable>;
478 : :
479 : : using CastReturnType = typename cast_retty<To, From>::ret_type;
480 : :
481 : 0 : static inline CastReturnType doCast(const From &f) {
482 : : return cast_convert_val<
483 : : To, From,
484 : 0 : typename simplify_type<From>::SimpleType>::doit(const_cast<From &>(f));
485 : : }
486 : :
487 : : // This assumes that you can construct the cast return type from `nullptr`.
488 : : // This is largely to support legacy use cases - if you don't want this
489 : : // behavior you should specialize CastInfo for your use case.
490 : 0 : static inline CastReturnType castFailed() { return CastReturnType(nullptr); }
491 : :
492 : 0 : static inline CastReturnType doCastIfPossible(const From &f) {
493 [ # # ]: 0 : if (!Self::isPossible(f))
494 : 0 : return castFailed();
495 : 0 : return doCast(f);
496 : : }
497 : : };
498 : :
499 : : /// This struct provides an overload for CastInfo where From has simplify_type
500 : : /// defined. This simply forwards to the appropriate CastInfo with the
501 : : /// simplified type/value, so you don't have to implement both.
502 : : template <typename To, typename From>
503 : : struct CastInfo<To, From, std::enable_if_t<!is_simple_type<From>::value>> {
504 : : using Self = CastInfo<To, From>;
505 : : using SimpleFrom = typename simplify_type<From>::SimpleType;
506 : : using SimplifiedSelf = CastInfo<To, SimpleFrom>;
507 : :
508 : 0 : static inline bool isPossible(From &f) {
509 : 0 : return SimplifiedSelf::isPossible(
510 [ # # # # ]: 0 : simplify_type<From>::getSimplifiedValue(f));
511 : : }
512 : :
513 : : static inline decltype(auto) doCast(From &f) {
514 : : return SimplifiedSelf::doCast(simplify_type<From>::getSimplifiedValue(f));
515 : : }
516 : :
517 : : static inline decltype(auto) castFailed() {
518 : : return SimplifiedSelf::castFailed();
519 : : }
520 : :
521 : 0 : static inline decltype(auto) doCastIfPossible(From &f) {
522 : 0 : return SimplifiedSelf::doCastIfPossible(
523 [ # # ]: 0 : simplify_type<From>::getSimplifiedValue(f));
524 : : }
525 : : };
526 : :
527 : : //===----------------------------------------------------------------------===//
528 : : // Pre-specialized CastInfo
529 : : //===----------------------------------------------------------------------===//
530 : :
531 : : /// Provide a CastInfo specialized for std::unique_ptr.
532 : : template <typename To, typename From>
533 : : struct CastInfo<To, std::unique_ptr<From>> : public UniquePtrCast<To, From> {};
534 : :
535 : : /// Provide a CastInfo specialized for std::optional<From>. It's assumed that if
536 : : /// the input is std::optional<From> that the output can be std::optional<To>.
537 : : /// If that's not the case, specialize CastInfo for your use case.
538 : : template <typename To, typename From>
539 : : struct CastInfo<To, std::optional<From>> : public OptionalValueCast<To, From> {
540 : : };
541 : :
542 : : /// isa<X> - Return true if the parameter to the template is an instance of one
543 : : /// of the template type arguments. Used like this:
544 : : ///
545 : : /// if (isa<Type>(myVal)) { ... }
546 : : /// if (isa<Type0, Type1, Type2>(myVal)) { ... }
547 : : template <typename To, typename From>
548 : 0 : [[nodiscard]] inline bool isa(const From &Val) {
549 : 0 : return CastInfo<To, const From>::isPossible(Val);
550 : : }
551 : :
552 : : template <typename First, typename Second, typename... Rest, typename From>
553 : : [[nodiscard]] inline bool isa(const From &Val) {
554 : : return isa<First>(Val) || isa<Second, Rest...>(Val);
555 : : }
556 : :
557 : : /// cast<X> - Return the argument parameter cast to the specified type. This
558 : : /// casting operator asserts that the type is correct, so it does not return
559 : : /// null on failure. It does not allow a null argument (use cast_if_present for
560 : : /// that). It is typically used like this:
561 : : ///
562 : : /// cast<Instruction>(myVal)->getParent()
563 : :
564 : : template <typename To, typename From>
565 : 0 : [[nodiscard]] inline decltype(auto) cast(const From &Val) {
566 [ # # ]: 0 : assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
567 : 0 : return CastInfo<To, const From>::doCast(Val);
568 : : }
569 : :
570 : : template <typename To, typename From>
571 : : [[nodiscard]] inline decltype(auto) cast(From &Val) {
572 : : assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
573 : : return CastInfo<To, From>::doCast(Val);
574 : : }
575 : :
576 : : template <typename To, typename From>
577 : 0 : [[nodiscard]] inline decltype(auto) cast(From *Val) {
578 [ # # ]: 0 : assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
579 : 0 : return CastInfo<To, From *>::doCast(Val);
580 : : }
581 : :
582 : : template <typename To, typename From>
583 : : [[nodiscard]] inline decltype(auto) cast(std::unique_ptr<From> &&Val) {
584 : : assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
585 : : return CastInfo<To, std::unique_ptr<From>>::doCast(std::move(Val));
586 : : }
587 : :
588 : : //===----------------------------------------------------------------------===//
589 : : // ValueIsPresent
590 : : //===----------------------------------------------------------------------===//
591 : :
592 : : template <typename T>
593 : : constexpr bool IsNullable =
594 : : std::is_pointer_v<T> || std::is_constructible_v<T, std::nullptr_t>;
595 : :
596 : : /// ValueIsPresent provides a way to check if a value is, well, present. For
597 : : /// pointers, this is the equivalent of checking against nullptr, for Optionals
598 : : /// this is the equivalent of checking hasValue(). It also provides a method for
599 : : /// unwrapping a value (think calling .value() on an optional).
600 : :
601 : : // Generic values can't *not* be present.
602 : : template <typename T, typename Enable = void> struct ValueIsPresent {
603 : : using UnwrappedType = T;
604 : : static inline bool isPresent(const T &t) { return true; }
605 : : static inline decltype(auto) unwrapValue(T &t) { return t; }
606 : : };
607 : :
608 : : // Optional provides its own way to check if something is present.
609 : : template <typename T> struct ValueIsPresent<std::optional<T>> {
610 : : using UnwrappedType = T;
611 : : static inline bool isPresent(const std::optional<T> &t) {
612 : : return t.has_value();
613 : : }
614 : : static inline decltype(auto) unwrapValue(std::optional<T> &t) { return *t; }
615 : : };
616 : :
617 : : // If something is "nullable" then we just compare it to nullptr to see if it
618 : : // exists.
619 : : template <typename T>
620 : : struct ValueIsPresent<T, std::enable_if_t<IsNullable<T>>> {
621 : : using UnwrappedType = T;
622 : 0 : static inline bool isPresent(const T &t) { return t != T(nullptr); }
623 : 0 : static inline decltype(auto) unwrapValue(T &t) { return t; }
624 : : };
625 : :
626 : : namespace detail {
627 : : // Convenience function we can use to check if a value is present. Because of
628 : : // simplify_type, we have to call it on the simplified type for now.
629 : 0 : template <typename T> inline bool isPresent(const T &t) {
630 : 0 : return ValueIsPresent<typename simplify_type<T>::SimpleType>::isPresent(
631 : 0 : simplify_type<T>::getSimplifiedValue(const_cast<T &>(t)));
632 : : }
633 : :
634 : : // Convenience function we can use to unwrap a value.
635 : 0 : template <typename T> inline decltype(auto) unwrapValue(T &t) {
636 : 0 : return ValueIsPresent<T>::unwrapValue(t);
637 : : }
638 : : } // namespace detail
639 : :
640 : : /// dyn_cast<X> - Return the argument parameter cast to the specified type. This
641 : : /// casting operator returns null if the argument is of the wrong type, so it
642 : : /// can be used to test for a type as well as cast if successful. The value
643 : : /// passed in must be present, if not, use dyn_cast_if_present. This should be
644 : : /// used in the context of an if statement like this:
645 : : ///
646 : : /// if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... }
647 : :
648 : : template <typename To, typename From>
649 : : [[nodiscard]] inline decltype(auto) dyn_cast(const From &Val) {
650 : : assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
651 : : return CastInfo<To, const From>::doCastIfPossible(Val);
652 : : }
653 : :
654 : : template <typename To, typename From>
655 : 0 : [[nodiscard]] inline decltype(auto) dyn_cast(From &Val) {
656 [ # # ]: 0 : assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
657 : 0 : return CastInfo<To, From>::doCastIfPossible(Val);
658 : : }
659 : :
660 : : template <typename To, typename From>
661 : 0 : [[nodiscard]] inline decltype(auto) dyn_cast(From *Val) {
662 [ # # ]: 0 : assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
663 : 0 : return CastInfo<To, From *>::doCastIfPossible(Val);
664 : : }
665 : :
666 : : template <typename To, typename From>
667 : : [[nodiscard]] inline decltype(auto) dyn_cast(std::unique_ptr<From> &Val) {
668 : : assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
669 : : return CastInfo<To, std::unique_ptr<From>>::doCastIfPossible(Val);
670 : : }
671 : :
672 : : /// isa_and_present<X> - Functionally identical to isa, except that a null value
673 : : /// is accepted.
674 : : template <typename... X, class Y>
675 : : [[nodiscard]] inline bool isa_and_present(const Y &Val) {
676 : : if (!detail::isPresent(Val))
677 : : return false;
678 : : return isa<X...>(Val);
679 : : }
680 : :
681 : : template <typename... X, class Y>
682 : : [[nodiscard]] inline bool isa_and_nonnull(const Y &Val) {
683 : : return isa_and_present<X...>(Val);
684 : : }
685 : :
686 : : /// cast_if_present<X> - Functionally identical to cast, except that a null
687 : : /// value is accepted.
688 : : template <class X, class Y>
689 : : [[nodiscard]] inline auto cast_if_present(const Y &Val) {
690 : : if (!detail::isPresent(Val))
691 : : return CastInfo<X, const Y>::castFailed();
692 : : assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
693 : : return cast<X>(detail::unwrapValue(Val));
694 : : }
695 : :
696 : : template <class X, class Y> [[nodiscard]] inline auto cast_if_present(Y &Val) {
697 : : if (!detail::isPresent(Val))
698 : : return CastInfo<X, Y>::castFailed();
699 : : assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
700 : : return cast<X>(detail::unwrapValue(Val));
701 : : }
702 : :
703 : : template <class X, class Y> [[nodiscard]] inline auto cast_if_present(Y *Val) {
704 : : if (!detail::isPresent(Val))
705 : : return CastInfo<X, Y *>::castFailed();
706 : : assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
707 : : return cast<X>(detail::unwrapValue(Val));
708 : : }
709 : :
710 : : template <class X, class Y>
711 : : [[nodiscard]] inline auto cast_if_present(std::unique_ptr<Y> &&Val) {
712 : : if (!detail::isPresent(Val))
713 : : return UniquePtrCast<X, Y>::castFailed();
714 : : return UniquePtrCast<X, Y>::doCast(std::move(Val));
715 : : }
716 : :
717 : : // Provide a forwarding from cast_or_null to cast_if_present for current
718 : : // users. This is deprecated and will be removed in a future patch, use
719 : : // cast_if_present instead.
720 : : template <class X, class Y> auto cast_or_null(const Y &Val) {
721 : : return cast_if_present<X>(Val);
722 : : }
723 : :
724 : : template <class X, class Y> auto cast_or_null(Y &Val) {
725 : : return cast_if_present<X>(Val);
726 : : }
727 : :
728 : : template <class X, class Y> auto cast_or_null(Y *Val) {
729 : : return cast_if_present<X>(Val);
730 : : }
731 : :
732 : : template <class X, class Y> auto cast_or_null(std::unique_ptr<Y> &&Val) {
733 : : return cast_if_present<X>(std::move(Val));
734 : : }
735 : :
736 : : /// dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a
737 : : /// null (or none in the case of optionals) value is accepted.
738 : : template <class X, class Y> auto dyn_cast_if_present(const Y &Val) {
739 : : if (!detail::isPresent(Val))
740 : : return CastInfo<X, const Y>::castFailed();
741 : : return CastInfo<X, const Y>::doCastIfPossible(detail::unwrapValue(Val));
742 : : }
743 : :
744 : : template <class X, class Y> auto dyn_cast_if_present(Y &Val) {
745 : : if (!detail::isPresent(Val))
746 : : return CastInfo<X, Y>::castFailed();
747 : : return CastInfo<X, Y>::doCastIfPossible(detail::unwrapValue(Val));
748 : : }
749 : :
750 : 0 : template <class X, class Y> auto dyn_cast_if_present(Y *Val) {
751 [ # # ]: 0 : if (!detail::isPresent(Val))
752 : 0 : return CastInfo<X, Y *>::castFailed();
753 : 0 : return CastInfo<X, Y *>::doCastIfPossible(detail::unwrapValue(Val));
754 : : }
755 : :
756 : : // Forwards to dyn_cast_if_present to avoid breaking current users. This is
757 : : // deprecated and will be removed in a future patch, use
758 : : // cast_if_present instead.
759 : : template <class X, class Y> auto dyn_cast_or_null(const Y &Val) {
760 : : return dyn_cast_if_present<X>(Val);
761 : : }
762 : :
763 : : template <class X, class Y> auto dyn_cast_or_null(Y &Val) {
764 : : return dyn_cast_if_present<X>(Val);
765 : : }
766 : :
767 : 0 : template <class X, class Y> auto dyn_cast_or_null(Y *Val) {
768 : 0 : return dyn_cast_if_present<X>(Val);
769 : : }
770 : :
771 : : /// unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>,
772 : : /// taking ownership of the input pointer iff isa<X>(Val) is true. If the
773 : : /// cast is successful, From refers to nullptr on exit and the casted value
774 : : /// is returned. If the cast is unsuccessful, the function returns nullptr
775 : : /// and From is unchanged.
776 : : template <class X, class Y>
777 : : [[nodiscard]] inline typename CastInfo<X, std::unique_ptr<Y>>::CastResultType
778 : : unique_dyn_cast(std::unique_ptr<Y> &Val) {
779 : : if (!isa<X>(Val))
780 : : return nullptr;
781 : : return cast<X>(std::move(Val));
782 : : }
783 : :
784 : : template <class X, class Y>
785 : : [[nodiscard]] inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val) {
786 : : return unique_dyn_cast<X, Y>(Val);
787 : : }
788 : :
789 : : // unique_dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast,
790 : : // except that a null value is accepted.
791 : : template <class X, class Y>
792 : : [[nodiscard]] inline typename CastInfo<X, std::unique_ptr<Y>>::CastResultType
793 : : unique_dyn_cast_or_null(std::unique_ptr<Y> &Val) {
794 : : if (!Val)
795 : : return nullptr;
796 : : return unique_dyn_cast<X, Y>(Val);
797 : : }
798 : :
799 : : template <class X, class Y>
800 : : [[nodiscard]] inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val) {
801 : : return unique_dyn_cast_or_null<X, Y>(Val);
802 : : }
803 : :
804 : : //===----------------------------------------------------------------------===//
805 : : // Isa Predicates
806 : : //===----------------------------------------------------------------------===//
807 : :
808 : : /// These are wrappers over isa* function that allow them to be used in generic
809 : : /// algorithms such as `llvm:all_of`, `llvm::none_of`, etc. This is accomplished
810 : : /// by exposing the isa* functions through function objects with a generic
811 : : /// function call operator.
812 : :
813 : : namespace detail {
814 : : template <typename... Types> struct IsaCheckPredicate {
815 : : template <typename T> [[nodiscard]] bool operator()(const T &Val) const {
816 : : return isa<Types...>(Val);
817 : : }
818 : : };
819 : :
820 : : template <typename... Types> struct IsaAndPresentCheckPredicate {
821 : : template <typename T> [[nodiscard]] bool operator()(const T &Val) const {
822 : : return isa_and_present<Types...>(Val);
823 : : }
824 : : };
825 : : } // namespace detail
826 : :
827 : : /// Function object wrapper for the `llvm::isa` type check. The function call
828 : : /// operator returns true when the value can be cast to any type in `Types`.
829 : : /// Example:
830 : : /// ```
831 : : /// SmallVector<Type> myTypes = ...;
832 : : /// if (llvm::all_of(myTypes, llvm::IsaPred<VectorType>))
833 : : /// ...
834 : : /// ```
835 : : template <typename... Types>
836 : : inline constexpr detail::IsaCheckPredicate<Types...> IsaPred{};
837 : :
838 : : /// Function object wrapper for the `llvm::isa_and_present` type check. The
839 : : /// function call operator returns true when the value can be cast to any type
840 : : /// in `Types`, or if the value is not present (e.g., nullptr). Example:
841 : : /// ```
842 : : /// SmallVector<Type> myTypes = ...;
843 : : /// if (llvm::all_of(myTypes, llvm::IsaAndPresentPred<VectorType>))
844 : : /// ...
845 : : /// ```
846 : : template <typename... Types>
847 : : inline constexpr detail::IsaAndPresentCheckPredicate<Types...>
848 : : IsaAndPresentPred{};
849 : :
850 : : } // end namespace llvm
851 : :
852 : : #endif // LLVM_SUPPORT_CASTING_H
|